From ba8f27fa76279aee680ec1d94841cf431951da95 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 15 Mar 2023 12:32:23 +0200 Subject: [PATCH] Notification system refactoring and improvements --- .../main/data/upgrade/3.4.4/schema_update.sql | 24 ++-- .../server/actors/tenant/TenantActor.java | 1 + .../NotificationRuleController.java | 8 +- .../NotificationTargetController.java | 10 +- .../NotificationExecutorService.java | 6 +- .../DefaultNotificationCenter.java | 50 +++----- ...aultNotificationRuleProcessingService.java | 120 ++++++++---------- .../trigger/AlarmCommentTriggerProcessor.java | 10 +- .../DeviceInactivityTriggerProcessor.java | 10 +- .../trigger/EntityActionTriggerProcessor.java | 8 +- ...neMsgNotificationRuleTriggerProcessor.java | 27 ++++ .../queue/DefaultTbCoreConsumerService.java | 3 +- .../DefaultTbRuleEngineConsumerService.java | 4 +- .../processing/AbstractConsumerService.java | 4 - .../service/ws/DefaultWebSocketService.java | 3 +- .../DefaultNotificationCommandsHandler.java | 108 +++++++--------- .../sub/NotificationRequestUpdate.java | 2 - .../notification/sub/NotificationUpdate.java | 10 +- .../src/main/resources/thingsboard.yml | 3 - .../AbstractNotificationApiTest.java | 8 +- .../notification/NotificationApiTest.java | 63 +++------ .../notification/NotificationRuleApiTest.java | 24 ++-- .../NotificationTemplateApiTest.java | 6 +- .../NotificationRequestService.java | 2 +- .../dao/notification/NotificationService.java | 2 - .../server/dao/user/UserService.java | 2 +- .../server/common/data/CacheConstants.java | 1 - .../data/notification/Notification.java | 11 -- .../NotificationDeliveryMethod.java | 2 +- .../NotificationProcessingContext.java | 10 +- .../trigger/NotificationRuleTriggerType.java | 17 +-- .../targets/NotificationTargetType.java | 2 +- .../targets/platform/UsersFilterType.java | 4 - .../DeliveryMethodNotificationTemplate.java | 2 +- ...ebDeliveryMethodNotificationTemplate.java} | 10 +- .../DefaultNotificationRequestService.java | 39 +----- .../DefaultNotificationService.java | 6 - .../DefaultNotificationTargetService.java | 2 +- .../dao/notification/NotificationDao.java | 2 - .../cache/NotificationRequestCacheKey.java | 43 ------- .../cache/NotificationRequestCacheValue.java | 38 ------ .../NotificationRequestCaffeineCache.java | 32 ----- .../cache/NotificationRequestRedisCache.java | 35 ----- .../sql/notification/JpaNotificationDao.java | 5 - .../JpaNotificationRequestDao.java | 2 +- .../notification/NotificationRepository.java | 7 - .../NotificationRequestRepository.java | 2 +- .../server/dao/user/UserServiceImpl.java | 2 +- .../resources/sql/schema-entities-idx.sql | 3 + .../main/resources/sql/schema-entities.sql | 1 - .../rule/engine/api/NotificationCenter.java | 2 - 51 files changed, 275 insertions(+), 523 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java rename common/data/src/main/java/org/thingsboard/server/common/data/notification/template/{PushDeliveryMethodNotificationTemplate.java => WebDeliveryMethodNotificationTemplate.java} (77%) delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java diff --git a/application/src/main/data/upgrade/3.4.4/schema_update.sql b/application/src/main/data/upgrade/3.4.4/schema_update.sql index 75cb42e1cf..7030ff7af1 100644 --- a/application/src/main/data/upgrade/3.4.4/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.4/schema_update.sql @@ -89,6 +89,10 @@ CREATE TABLE IF NOT EXISTS alarm_comment ( ) PARTITION BY RANGE (created_time); CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id); +-- ALARM COMMENTS END + +-- NOTIFICATIONS START + CREATE TABLE IF NOT EXISTS notification_target ( id UUID NOT NULL CONSTRAINT notification_target_pkey PRIMARY KEY, created_time BIGINT NOT NULL, @@ -122,7 +126,7 @@ CREATE TABLE IF NOT EXISTS notification_rule ( additional_config VARCHAR(255), CONSTRAINT uq_notification_rule_name UNIQUE (tenant_id, name) ); -CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_created_time ON notification_rule(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_trigger_type_created_time ON notification_rule(tenant_id, trigger_type, created_time DESC); CREATE TABLE IF NOT EXISTS notification_request ( id UUID NOT NULL CONSTRAINT notification_request_pkey PRIMARY KEY, @@ -139,9 +143,12 @@ CREATE TABLE IF NOT EXISTS notification_request ( status VARCHAR(32), stats VARCHAR(10000) ); -CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_originator_type_created_time ON notification_request(tenant_id, originator_entity_type, created_time DESC); -CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id); -CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status); +CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_user_created_time ON notification_request(tenant_id, created_time DESC) + WHERE originator_entity_type = 'USER'; +CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id) + WHERE originator_entity_type = 'ALARM'; +CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status) + WHERE status = 'SCHEDULED'; CREATE TABLE IF NOT EXISTS notification ( id UUID NOT NULL, @@ -152,11 +159,12 @@ CREATE TABLE IF NOT EXISTS notification ( subject VARCHAR(255), text VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), - info VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); -CREATE INDEX IF NOT EXISTS idx_notification_id_recipient_id ON notification(id, recipient_id); -CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_status_created_time ON notification(recipient_id, status, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_notification_id ON notification(id); +CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notification(recipient_id, created_time DESC); + +-- NOTIFICATIONS END ALTER TABLE tb_user ADD COLUMN IF NOT EXISTS phone VARCHAR(255); @@ -166,8 +174,6 @@ CREATE TABLE IF NOT EXISTS user_settings ( CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id) ON DELETE CASCADE ); --- ALARM COMMENTS END - -- ALARM INFO VIEW DROP VIEW IF EXISTS alarm_info CASCADE; diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index e176895ac8..dc9413bf2d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -208,6 +208,7 @@ public class TenantActor extends RuleChainManagerActor { log.trace("[{}] Ack message because Rule Engine is disabled", tenantId); tbMsg.getCallback().onSuccess(); } + systemContext.getNotificationRuleProcessingService().process(tenantId, tbMsg); } private void onRuleChainMsg(RuleChainAwareMsg msg) { diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java index 8c08e1eab2..fe326ef6b8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java @@ -55,7 +55,7 @@ public class NotificationRuleController extends BaseController { private final NotificationRuleService notificationRuleService; @PostMapping("/rule") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRule saveNotificationRule(@RequestBody @Valid NotificationRule notificationRule) throws Exception { notificationRule.setTenantId(getTenantId()); checkEntity(notificationRule.getId(), notificationRule, NOTIFICATION); @@ -63,14 +63,14 @@ public class NotificationRuleController extends BaseController { } @GetMapping("/rule/{id}") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public NotificationRuleInfo getNotificationRuleById(@PathVariable UUID id) throws ThingsboardException { NotificationRuleId notificationRuleId = new NotificationRuleId(id); return checkEntityId(notificationRuleId, notificationRuleService::findNotificationRuleInfoById, Operation.READ); } @GetMapping("/rules") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public PageData getNotificationRules(@RequestParam int pageSize, @RequestParam int page, @RequestParam(required = false) String textSearch, @@ -83,7 +83,7 @@ public class NotificationRuleController extends BaseController { } @DeleteMapping("/rule/{id}") - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") public void deleteNotificationRule(@PathVariable UUID id, @AuthenticationPrincipal SecurityUser user) throws Exception { NotificationRuleId notificationRuleId = new NotificationRuleId(id); diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java index b07cff0849..4f4380c2df 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java @@ -33,15 +33,16 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.NotificationTargetId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; +import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -159,11 +160,8 @@ public class NotificationTargetController extends BaseController { // generic permission for users UsersFilter usersFilter = ((PlatformUsersNotificationTargetConfig) targetConfig).getUsersFilter(); if (usersFilter.getType() == UsersFilterType.USER_LIST) { - PageDataIterable recipients = new PageDataIterable<>(pageLink -> { - return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), null, targetConfig, pageLink); - }, 200); - for (User recipient : recipients) { - checkEntity(user, recipient, Operation.READ); + for (UUID recipientId : ((UserListFilter) usersFilter).getUsersIds()) { + checkUserId(new UserId(recipientId), Operation.READ); } } else if (usersFilter.getType() == UsersFilterType.CUSTOMER_USERS) { CustomerId customerId = new CustomerId(((CustomerUsersFilter) usersFilter).getCustomerId()); diff --git a/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java b/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java index 39b472c988..53d55fdad6 100644 --- a/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java +++ b/application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java @@ -22,12 +22,12 @@ import org.thingsboard.common.util.AbstractListeningExecutor; @Component public class NotificationExecutorService extends AbstractListeningExecutor { - @Value("${notification_system.thread_pool_size}") - private int notificationSystemExecutorThreadPoolSize; + @Value("${notification_system.thread_pool_size:30}") + private int threadPoolSize; @Override protected int getThreadPollSize() { - return notificationSystemExecutorThreadPoolSize; + return threadPoolSize; } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 0f165fb0d8..81c0fbf6a5 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -45,7 +45,7 @@ import org.thingsboard.server.common.data.notification.targets.NotificationTarge 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; -import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -82,7 +82,7 @@ import java.util.stream.Collectors; @Slf4j @RequiredArgsConstructor @SuppressWarnings({"UnstableApiUsage", "rawtypes"}) -public class DefaultNotificationCenter extends AbstractSubscriptionService implements NotificationCenter, NotificationChannel { +public class DefaultNotificationCenter extends AbstractSubscriptionService implements NotificationCenter, NotificationChannel { private final NotificationTargetService notificationTargetService; private final NotificationRequestService notificationRequestService; @@ -93,6 +93,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple private final DbCallbackExecutorService dbCallbackExecutorService; private final NotificationsTopicService notificationsTopicService; private final TbQueueProducerProvider producerProvider; + private Map channels; @@ -244,7 +245,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Override - public ListenableFuture sendNotification(User recipient, PushDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) { + public ListenableFuture sendNotification(User recipient, WebDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) { NotificationRequest request = ctx.getRequest(); Notification notification = Notification.builder() .requestId(request.getId()) @@ -264,8 +265,8 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } NotificationUpdate update = NotificationUpdate.builder() + .created(true) .notification(notification) - .updateType(ComponentLifecycleEvent.CREATED) .build(); return onNotificationUpdate(recipient.getTenantId(), recipient.getId(), update); } @@ -282,8 +283,8 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple notification = notificationService.saveNotification(TenantId.SYS_TENANT_ID, notification); NotificationUpdate update = NotificationUpdate.builder() + .created(true) .notification(notification) - .updateType(ComponentLifecycleEvent.CREATED) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -294,9 +295,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (updated) { log.trace("Marked notification {} as read (recipient id: {}, tenant id: {})", notificationId, recipientId, tenantId); NotificationUpdate update = NotificationUpdate.builder() + .updated(true) .notificationId(notificationId) - .updatedStatus(NotificationStatus.READ) - .updateType(ComponentLifecycleEvent.UPDATED) + .newStatus(NotificationStatus.READ) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -308,9 +309,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (updatedCount > 0) { log.trace("Marked all notifications as read (recipient id: {}, tenant id: {})", recipientId, tenantId); NotificationUpdate update = NotificationUpdate.builder() + .updated(true) .allNotifications(true) - .updatedStatus(NotificationStatus.READ) - .updateType(ComponentLifecycleEvent.UPDATED) + .newStatus(NotificationStatus.READ) .build(); onNotificationUpdate(tenantId, recipientId, update); } @@ -322,43 +323,28 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple boolean deleted = notificationService.deleteNotification(tenantId, recipientId, notificationId); if (deleted) { NotificationUpdate update = NotificationUpdate.builder() + .deleted(true) .notification(notification) - .updateType(ComponentLifecycleEvent.DELETED) .build(); onNotificationUpdate(tenantId, recipientId, update); } } - @Override - public NotificationRequest updateNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { - log.debug("Updating notification request {}", notificationRequest.getId()); - notificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest); - // marking related notifications as unread: TODO: causes each subscription to fetch notifications on each request update - notificationService.updateNotificationsStatusByRequestId(tenantId, notificationRequest.getId(), NotificationStatus.SENT); - - // TODO: no need to send request update for other than PLATFORM_USERS target type - onNotificationRequestUpdate(tenantId, NotificationRequestUpdate.builder() - .notificationRequestId(notificationRequest.getId()) - .notificationInfo(notificationRequest.getInfo()) - .deleted(false) - .build()); - return notificationRequest; - } - @Override public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId) { log.debug("Deleting notification request {}", notificationRequestId); NotificationRequest notificationRequest = notificationRequestService.findNotificationRequestById(tenantId, notificationRequestId); - notificationRequestService.deleteNotificationRequest(tenantId, notificationRequest); + notificationRequestService.deleteNotificationRequest(tenantId, notificationRequestId); - // TODO: no need to send request update for other than PLATFORM_USERS target type if (notificationRequest.isSent()) { + // TODO: no need to send request update for other than PLATFORM_USERS target type onNotificationRequestUpdate(tenantId, NotificationRequestUpdate.builder() .notificationRequestId(notificationRequestId) .deleted(true) .build()); + } else if (notificationRequest.isScheduled()) { + clusterService.broadcastEntityStateChangeEvent(tenantId, notificationRequestId, ComponentLifecycleEvent.DELETED); } - clusterService.broadcastEntityStateChangeEvent(tenantId, notificationRequestId, ComponentLifecycleEvent.DELETED); } private void forwardToNotificationSchedulerService(TenantId tenantId, NotificationRequestId notificationRequestId) { @@ -397,7 +383,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple @Override public NotificationDeliveryMethod getDeliveryMethod() { - return NotificationDeliveryMethod.PUSH; + return NotificationDeliveryMethod.WEB; } @Override @@ -406,9 +392,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Autowired - public void setChannels(List channels, NotificationCenter websocketNotificationChannel) { + public void setChannels(List channels, NotificationCenter webNotificationChannel) { this.channels = channels.stream().collect(Collectors.toMap(NotificationChannel::getDeliveryMethod, c -> c)); - this.channels.put(NotificationDeliveryMethod.PUSH, (NotificationChannel) websocketNotificationChannel); + this.channels.put(NotificationDeliveryMethod.WEB, (NotificationChannel) webNotificationChannel); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java index c17b8f3bcd..c62c03f1f5 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java @@ -15,16 +15,13 @@ */ package org.thingsboard.server.service.notification.rule; -import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.rule.engine.api.NotificationCenter; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.EntityId; @@ -44,49 +41,45 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 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.queue.discovery.PartitionService; 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 org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor; import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @Service @RequiredArgsConstructor @Slf4j +@SuppressWarnings("rawtypes") public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService { private final NotificationRuleService notificationRuleService; private final NotificationRequestService notificationRequestService; @Autowired @Lazy private NotificationCenter notificationCenter; - private Map triggerProcessors; - private final NotificationExecutorService notificationExecutor; - private final DbCallbackExecutorService dbCallbackExecutor; - private final Map msgTypeToTriggerType = Map.of( - 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.COMMENT_CREATED, NotificationRuleTriggerType.ALARM_COMMENT, - DataConstants.COMMENT_UPDATED, NotificationRuleTriggerType.ALARM_COMMENT - ); + private final Map triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class); + + private final Map ruleEngineMsgTypeToTriggerType = new HashMap<>(); @Override public void process(TenantId tenantId, TbMsg ruleEngineMsg) { String msgType = ruleEngineMsg.getType(); - NotificationRuleTriggerType triggerType = msgTypeToTriggerType.get(msgType); + NotificationRuleTriggerType triggerType = ruleEngineMsgTypeToTriggerType.get(msgType); if (triggerType == null) { return; } - processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg); } @@ -113,55 +106,37 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul } private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId, Object triggerObject) { - ListenableFuture> rulesFuture = dbCallbackExecutor.submit(() -> { - return notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); - }); - DonAsynchron.withCallback(rulesFuture, rules -> { - for (NotificationRule rule : rules) { - notificationExecutor.submit(() -> { - processNotificationRule(rule, originatorEntityId, triggerObject); - }); - } - }, e -> { - log.error("Failed to find notification rules by trigger type {}", triggerType, e); - }); + List rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType); + for (NotificationRule rule : rules) { + notificationExecutor.submit(() -> { + processNotificationRule(rule, originatorEntityId, triggerObject); + }); + } } 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()) { + if (matchesClearRule(triggerObject, triggerConfig)) { List notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), originatorEntityId); - if (!notificationRequests.isEmpty()) { - if (matchesClearRule(triggerObject, triggerConfig)) { - notificationRequests = notificationRequests.stream() - .filter(notificationRequest -> { - if (!notificationRequest.isSent()) { - dbCallbackExecutor.submit(() -> { - notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); - }); - return false; - } else { - return true; - } - }) - .collect(Collectors.toList()); - // not returning because we need to update notifications if any - } - - NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); - for (NotificationRequest notificationRequest : notificationRequests) { - NotificationInfo previousNotificationInfo = notificationRequest.getInfo(); - if (!notificationInfo.equals(previousNotificationInfo)) { - notificationRequest.setInfo(notificationInfo); - dbCallbackExecutor.submit(() -> { - notificationCenter.updateNotificationRequest(rule.getTenantId(), notificationRequest); - }); - } - } + if (notificationRequests.isEmpty()) { return; } + + List targets = notificationRequests.stream() + .filter(NotificationRequest::isSent) + .flatMap(notificationRequest -> notificationRequest.getTargets().stream()) + .distinct().collect(Collectors.toList()); + NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); + submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, 0); + + notificationRequests.forEach(notificationRequest -> { + if (notificationRequest.isScheduled()) { + notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); + } + }); + return; } if (!matchesFilter(triggerObject, triggerConfig)) { @@ -170,14 +145,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig); rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> { - notificationExecutor.submit(() -> { - try { - log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delay, targets); - submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); - } catch (Exception e) { - log.error("Failed to submit notification request for rule {}", rule.getId(), e); - } - }); + submitNotificationRequest(targets, rule, originatorEntityId, notificationInfo, delay); }); } @@ -208,7 +176,14 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul .ruleId(rule.getId()) .originatorEntityId(originatorEntityId) .build(); - notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest); + notificationExecutor.submit(() -> { + try { + log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delayInSec, targets); + notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest); + } catch (Exception e) { + log.error("Failed to process notification request for rule {}", rule.getId(), e); + } + }); } @EventListener(ComponentLifecycleMsg.class) @@ -220,7 +195,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul TenantId tenantId = componentLifecycleMsg.getTenantId(); NotificationRuleId notificationRuleId = (NotificationRuleId) componentLifecycleMsg.getEntityId(); - dbCallbackExecutor.submit(() -> { + notificationExecutor.submit(() -> { List scheduledForRule = notificationRequestService.findNotificationRequestsIdsByStatusAndRuleId(tenantId, NotificationRequestStatus.SCHEDULED, notificationRuleId); for (NotificationRequestId notificationRequestId : scheduledForRule) { notificationCenter.deleteNotificationRequest(tenantId, notificationRequestId); @@ -230,8 +205,15 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul @Autowired public void setTriggerProcessors(Collection processors) { - this.triggerProcessors = processors.stream() - .collect(Collectors.toMap(NotificationRuleTriggerProcessor::getTriggerType, p -> p)); + processors.forEach(processor -> { + triggerProcessors.put(processor.getTriggerType(), processor); + if (processor instanceof RuleEngineMsgNotificationRuleTriggerProcessor) { + Set supportedMsgTypes = ((RuleEngineMsgNotificationRuleTriggerProcessor) processor).getSupportedMsgTypes(); + supportedMsgTypes.forEach(supportedMsgType -> { + ruleEngineMsgTypeToTriggerType.put(supportedMsgType, processor.getTriggerType()); + }); + } + }); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index 28a03830bf..cd30d9b580 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -17,6 +17,7 @@ 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.DataConstants; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; @@ -26,10 +27,12 @@ import org.thingsboard.server.common.data.notification.rule.trigger.AlarmComment import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Set; + import static org.apache.commons.collections.CollectionUtils.isEmpty; @Service -public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProcessor { +public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { @@ -61,4 +64,9 @@ public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProc return NotificationRuleTriggerType.ALARM_COMMENT; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.COMMENT_CREATED, DataConstants.COMMENT_UPDATED); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java index a193368b12..9f7c2d9401 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.notification.rule.trigger; import lombok.RequiredArgsConstructor; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -28,9 +29,11 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.service.profile.TbDeviceProfileCache; +import java.util.Set; + @Service @RequiredArgsConstructor -public class DeviceInactivityTriggerProcessor implements NotificationRuleTriggerProcessor { +public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { private final TbDeviceProfileCache deviceProfileCache; @@ -62,4 +65,9 @@ public class DeviceInactivityTriggerProcessor implements NotificationRuleTrigger return NotificationRuleTriggerType.DEVICE_INACTIVITY; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.INACTIVITY_EVENT); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java index 33ade0238a..60044dd96a 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java @@ -25,10 +25,11 @@ import org.thingsboard.server.common.data.notification.rule.trigger.EntityAction import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Set; import java.util.UUID; @Service -public class EntityActionTriggerProcessor implements NotificationRuleTriggerProcessor { +public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor { @Override public boolean matchesFilter(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) { @@ -73,4 +74,9 @@ public class EntityActionTriggerProcessor implements NotificationRuleTriggerProc return NotificationRuleTriggerType.ENTITY_ACTION; } + @Override + public Set getSupportedMsgTypes() { + return Set.of(DataConstants.ENTITY_CREATED, DataConstants.ENTITY_UPDATED, DataConstants.ENTITY_DELETED); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java new file mode 100644 index 0000000000..8d200c4ae3 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java @@ -0,0 +1,27 @@ +/** + * 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.service.notification.rule.trigger; + +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.Set; + +public interface RuleEngineMsgNotificationRuleTriggerProcessor extends NotificationRuleTriggerProcessor { + + Set getSupportedMsgTypes(); + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index baded64603..2e736fefe1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -156,10 +156,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService jwtSettingsService, NotificationSchedulerService notificationSchedulerService) { - super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, notificationRuleProcessingService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService); + super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService); this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer(); this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer(); this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 3bd2915465..4460654617 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -129,9 +129,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< TbTenantProfileCache tenantProfileCache, TbApiUsageStateService apiUsageStateService, PartitionService partitionService, ApplicationEventPublisher eventPublisher, - NotificationRuleProcessingService notificationRuleProcessingService, TbServiceInfoProvider serviceInfoProvider, QueueService queueService) { - super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, notificationRuleProcessingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); + super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); this.statisticsService = statisticsService; this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory; this.submitStrategyFactory = submitStrategyFactory; @@ -482,7 +481,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); actorContext.tell(msg); - notificationRuleProcessingService.process(tenantId, tbMsg); } @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index 460813af13..15471e25e1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.TbQueueConsumer; @@ -78,7 +77,6 @@ public abstract class AbstractConsumerService> nfConsumer; protected final Optional jwtSettingsService; @@ -88,7 +86,6 @@ public abstract class AbstractConsumerService> nfConsumer, Optional jwtSettingsService) { this.actorContext = actorContext; this.encodingService = encodingService; @@ -98,7 +95,6 @@ public abstract class AbstractConsumerService subscription.getLimit()) { - Set beyondLimit = subscription.getSortedNotifications().stream().skip(subscription.getLimit()) - .map(IdBased::getUuidId).collect(Collectors.toSet()); - beyondLimit.forEach(id -> subscription.getLatestUnreadNotifications().remove(id)); - } - sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); - break; - } - case UPDATED: { - if (update.getUpdatedStatus() == NotificationStatus.READ) { - if (update.isAllNotifications() || subscription.getLatestUnreadNotifications().containsKey(notificationId)) { - fetchUnreadNotifications(subscription); - sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); - } else { - subscription.getTotalUnreadCounter().decrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); - } - } else if (notification.getStatus() != NotificationStatus.READ) { - if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { - subscription.getLatestUnreadNotifications().put(notificationId, notification); - sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); - } - } - break; + if (update.isCreated()) { + subscription.getLatestUnreadNotifications().put(notificationId, notification); + subscription.getTotalUnreadCounter().incrementAndGet(); + if (subscription.getLatestUnreadNotifications().size() > subscription.getLimit()) { + Set beyondLimit = subscription.getSortedNotifications().stream().skip(subscription.getLimit()) + .map(IdBased::getUuidId).collect(Collectors.toSet()); + beyondLimit.forEach(id -> subscription.getLatestUnreadNotifications().remove(id)); } - case DELETED: { - if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); + } else if (update.isUpdated()) { + if (update.getNewStatus() == NotificationStatus.READ) { + if (update.isAllNotifications() || subscription.getLatestUnreadNotifications().containsKey(notificationId)) { fetchUnreadNotifications(subscription); sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); - } else if (notification.getStatus() != NotificationStatus.READ) { + } else { subscription.getTotalUnreadCounter().decrementAndGet(); sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); } - break; + } else if (notification.getStatus() != NotificationStatus.READ) { + if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + subscription.getLatestUnreadNotifications().put(notificationId, notification); + sendUpdate(subscription.getSessionId(), subscription.createPartialUpdate(notification)); + } + } + } else if (update.isDeleted()) { + if (subscription.getLatestUnreadNotifications().containsKey(notificationId)) { + fetchUnreadNotifications(subscription); + sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); + } else if (notification.getStatus() != NotificationStatus.READ) { + subscription.getTotalUnreadCounter().decrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createCountUpdate()); } } } private void handleNotificationRequestUpdate(NotificationsSubscription subscription, NotificationRequestUpdate update) { log.trace("[{}, subId: {}] Handling notification request update: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - fetchUnreadNotifications(subscription); // FIXME: figure out how not to fetch notifications on each request update... + fetchUnreadNotifications(subscription); sendUpdate(subscription.getSessionId(), subscription.createFullUpdate()); } @@ -191,47 +184,33 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH private void handleNotificationUpdate(NotificationsCountSubscription subscription, NotificationUpdate update) { log.trace("[{}, subId: {}] Handling notification update for count sub: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - Notification notification = update.getNotification(); - switch (update.getUpdateType()) { - case CREATED: { - subscription.getUnreadCounter().incrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); - break; - } - case UPDATED: { - if (update.getUpdatedStatus() == NotificationStatus.READ) { - if (update.isAllNotifications()) { - fetchUnreadNotificationsCount(subscription); - } else { - subscription.getUnreadCounter().decrementAndGet(); - } - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); - } - break; - } - case DELETED: { - if (notification.getStatus() != NotificationStatus.READ) { + if (update.isCreated()) { + subscription.getUnreadCounter().incrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); + } else if (update.isUpdated()) { + if (update.getNewStatus() == NotificationStatus.READ) { + if (update.isAllNotifications()) { + fetchUnreadNotificationsCount(subscription); + } else { subscription.getUnreadCounter().decrementAndGet(); - sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } - break; + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); + } + } else if (update.isDeleted()) { + if (update.getNotification().getStatus() != NotificationStatus.READ) { + subscription.getUnreadCounter().decrementAndGet(); + sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } } } private void handleNotificationRequestUpdate(NotificationsCountSubscription subscription, NotificationRequestUpdate update) { log.trace("[{}, subId: {}] Handling notification request update for count sub: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); - fetchUnreadNotificationsCount(subscription); // FIXME: figure out how not to fetch notifications on each request update... + fetchUnreadNotificationsCount(subscription); sendUpdate(subscription.getSessionId(), subscription.createUpdate()); } - private void sendUpdate(String sessionId, CmdUpdate update) { - log.trace("[{}, cmdId: {}] Sending WS update: {}", sessionId, update.getCmdId(), update); - wsService.sendWsMsg(sessionId, update); - } - - @Override public void handleMarkAsReadCmd(WebSocketSessionRef sessionRef, MarkNotificationsAsReadCmd cmd) { SecurityUser securityCtx = sessionRef.getSecurityCtx(); @@ -253,4 +232,9 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH localSubscriptionService.cancelSubscription(sessionRef.getSessionId(), cmd.getCmdId()); } + private void sendUpdate(String sessionId, CmdUpdate update) { + log.trace("[{}, cmdId: {}] Sending WS update: {}", sessionId, update.getCmdId(), update); + wsService.sendWsMsg(sessionId, update); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java index e3563a32f2..ebbcc716ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationRequestUpdate.java @@ -20,7 +20,6 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.NotificationRequestId; -import org.thingsboard.server.common.data.notification.info.NotificationInfo; @Data @NoArgsConstructor @@ -28,6 +27,5 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; @Builder public class NotificationRequestUpdate { private NotificationRequestId notificationRequestId; - private NotificationInfo notificationInfo; private boolean deleted; } diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java index be9bd8d5ae..beeb46b1ac 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java @@ -22,7 +22,6 @@ import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.NotificationId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import java.util.UUID; @@ -33,12 +32,15 @@ import java.util.UUID; public class NotificationUpdate { private NotificationId notificationId; + + private boolean created; private Notification notification; - boolean allNotifications; + private boolean updated; + private NotificationStatus newStatus; + private boolean allNotifications; - private NotificationStatus updatedStatus; - private ComponentLifecycleEvent updateType; + private boolean deleted; public UUID getNotificationId() { return notificationId != null ? notificationId.getId() : diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 08fd0eef1e..db194cb6e0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -440,9 +440,6 @@ cache: notificationRules: timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}" maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}" - notificationRequests: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}" - maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}" attributes: timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" diff --git a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java index 52d115a7dc..7988b5ae2e 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java @@ -44,7 +44,7 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate; 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 org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -101,7 +101,7 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest protected NotificationRequest submitNotificationRequest(List targets, String text, int delayInSec, NotificationDeliveryMethod... deliveryMethods) { if (deliveryMethods.length == 0) { - deliveryMethods = new NotificationDeliveryMethod[]{NotificationDeliveryMethod.PUSH}; + deliveryMethods = new NotificationDeliveryMethod[]{NotificationDeliveryMethod.WEB}; } NotificationTemplate notificationTemplate = createNotificationTemplate(DEFAULT_NOTIFICATION_TYPE, DEFAULT_NOTIFICATION_SUBJECT, text, deliveryMethods); return submitNotificationRequest(targets, notificationTemplate.getId(), delayInSec); @@ -137,8 +137,8 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) { DeliveryMethodNotificationTemplate deliveryMethodNotificationTemplate; switch (deliveryMethod) { - case PUSH: { - PushDeliveryMethodNotificationTemplate template = new PushDeliveryMethodNotificationTemplate(); + case WEB: { + WebDeliveryMethodNotificationTemplate template = new WebDeliveryMethodNotificationTemplate(); template.setSubject(subject); deliveryMethodNotificationTemplate = template; break; diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index bb2bbce14a..f9c9f2836b 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -48,7 +48,7 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate; 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 org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.page.PageData; @@ -209,7 +209,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { int notificationsCount = 20; wsClient.registerWaitForUpdate(notificationsCount); for (int i = 1; i <= notificationsCount; i++) { - submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.PUSH); + submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); } wsClient.waitForUpdate(true); assertThat(wsClient.getLastDataUpdate().getTotalUnreadCount()).isEqualTo(notificationsCount); @@ -266,32 +266,6 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(getMyNotifications(false, 10)).size().isZero(); } - @Test - public void whenNotificationRequestIsUpdated_thenUpdateNotifications() throws Exception { - wsClient.subscribeForUnreadNotifications(10); - wsClient.waitForReply(true); - - NotificationTarget notificationTarget = createNotificationTarget(customerUserId); - String notificationText = "Text"; - wsClient.registerWaitForUpdate(); - NotificationRequest notificationRequest = submitNotificationRequest(notificationTarget.getId(), notificationText); - wsClient.waitForUpdate(true); - Notification initialNotification = wsClient.getLastDataUpdate().getUpdate(); - loginCustomerUser(); - assertThat(getMyNotifications(false, 10)).singleElement().isEqualTo(initialNotification); - assertThat(initialNotification.getInfo()).isNotNull().isEqualTo(notificationRequest.getInfo()); - - wsClient.registerWaitForUpdate(); - UserOriginatedNotificationInfo newNotificationInfo = new UserOriginatedNotificationInfo(); - newNotificationInfo.setDescription("New description"); - notificationRequest.setInfo(newNotificationInfo); - notificationCenter.updateNotificationRequest(tenantId, notificationRequest); - wsClient.waitForUpdate(true); - Notification updatedNotification = wsClient.getLastDataUpdate().getNotifications().iterator().next(); - assertThat(updatedNotification.getInfo()).isEqualTo(newNotificationInfo); - assertThat(getMyNotifications(false, 10)).singleElement().isEqualTo(updatedNotification); - } - @Test public void testNotificationUpdatesForSeveralUsers() throws Exception { int usersCount = 150; @@ -319,7 +293,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { sessions.forEach((user, wsClient) -> wsClient.registerWaitForUpdate()); NotificationRequest notificationRequest = submitNotificationRequest(targets, "Hello, ${recipientEmail}", 0, - NotificationDeliveryMethod.PUSH); + NotificationDeliveryMethod.WEB); await().atMost(10, TimeUnit.SECONDS) .pollDelay(1, TimeUnit.SECONDS).pollInterval(500, TimeUnit.MILLISECONDS) .until(() -> { @@ -342,7 +316,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { await().atMost(2, TimeUnit.SECONDS) .until(() -> findNotificationRequest(notificationRequest.getId()).isSent()); NotificationRequestStats stats = getStats(notificationRequest.getId()); - assertThat(stats.getSent().get(NotificationDeliveryMethod.PUSH)).hasValue(usersCount); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).hasValue(usersCount); sessions.values().forEach(wsClient -> wsClient.registerWaitForUpdate()); deleteNotificationRequest(notificationRequest.getId()); @@ -393,17 +367,17 @@ public class NotificationApiTest extends AbstractNotificationApiTest { String requestorEmail = TENANT_ADMIN_EMAIL; NotificationTemplateConfig templateConfig = new NotificationTemplateConfig(); - templateConfig.setDefaultTextTemplate("Default message for SMS and PUSH: ${recipientEmail}"); + templateConfig.setDefaultTextTemplate("Default message for SMS and WEB: ${recipientEmail}"); templateConfig.setNotificationSubject("Default subject for EMAIL: ${recipientEmail}"); HashMap templates = new HashMap<>(); templateConfig.setDeliveryMethodsTemplates(templates); notificationTemplate.setConfiguration(templateConfig); - PushDeliveryMethodNotificationTemplate pushNotificationTemplate = new PushDeliveryMethodNotificationTemplate(); - pushNotificationTemplate.setEnabled(true); - // using default message for push - pushNotificationTemplate.setSubject("Subject for PUSH: ${recipientEmail}"); - templates.put(NotificationDeliveryMethod.PUSH, pushNotificationTemplate); + WebDeliveryMethodNotificationTemplate webNotificationTemplate = new WebDeliveryMethodNotificationTemplate(); + webNotificationTemplate.setEnabled(true); + // using default message for web + webNotificationTemplate.setSubject("Subject for WEB: ${recipientEmail}"); + templates.put(NotificationDeliveryMethod.WEB, webNotificationTemplate); SmsDeliveryMethodNotificationTemplate smsNotificationTemplate = new SmsDeliveryMethodNotificationTemplate(); smsNotificationTemplate.setEnabled(true); @@ -435,19 +409,19 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(preview.getTotalRecipientsCount()).isEqualTo(1 + customerUsersCount); Map processedTemplates = preview.getProcessedTemplates(); - assertThat(processedTemplates.get(NotificationDeliveryMethod.PUSH)).asInstanceOf(type(PushDeliveryMethodNotificationTemplate.class)) + assertThat(processedTemplates.get(NotificationDeliveryMethod.WEB)).asInstanceOf(type(WebDeliveryMethodNotificationTemplate.class)) .satisfies(template -> { assertThat(template.getBody()) - .startsWith("Default message for SMS and PUSH") + .startsWith("Default message for SMS and WEB") .endsWith(requestorEmail); assertThat(template.getSubject()) - .startsWith("Subject for PUSH") + .startsWith("Subject for WEB") .endsWith(requestorEmail); }); assertThat(processedTemplates.get(NotificationDeliveryMethod.SMS)).asInstanceOf(type(SmsDeliveryMethodNotificationTemplate.class)) .satisfies(template -> { assertThat(template.getBody()) - .startsWith("Default message for SMS and PUSH") + .startsWith("Default message for SMS and WEB") .endsWith(requestorEmail); }); assertThat(processedTemplates.get(NotificationDeliveryMethod.EMAIL)).asInstanceOf(type(EmailDeliveryMethodNotificationTemplate.class)) @@ -469,7 +443,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { @Test public void testNotificationRequestInfo() throws Exception { NotificationDeliveryMethod[] deliveryMethods = new NotificationDeliveryMethod[]{ - NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL + NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL }; NotificationTemplate template = createNotificationTemplate(NotificationType.GENERAL, "Test subject", "Test text", deliveryMethods); NotificationTarget target = createNotificationTarget(tenantAdminUserId); @@ -489,15 +463,14 @@ public class NotificationApiTest extends AbstractNotificationApiTest { wsClient.registerWaitForUpdate(); NotificationTarget notificationTarget = createNotificationTarget(customerUserId); NotificationRequest notificationRequest = submitNotificationRequest(notificationTarget.getId(), "Test :)", - NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS); + NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS); wsClient.waitForUpdate(); await().atMost(2, TimeUnit.SECONDS) .until(() -> findNotificationRequest(notificationRequest.getId()).isSent()); NotificationRequestStats stats = getStats(notificationRequest.getId()); - assertThat(stats.getSent().get(NotificationDeliveryMethod.PUSH)).hasValue(1); - assertThat(stats.getSent().get(NotificationDeliveryMethod.EMAIL)).hasValue(1); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).hasValue(1); assertThat(stats.getErrors().get(NotificationDeliveryMethod.SMS)).size().isOne(); } @@ -526,7 +499,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { NotificationTargetId notificationTargetId = notificationTarget.getId(); ListenableFuture request = executor.submit(() -> { - return submitNotificationRequest(notificationTargetId, "Hello, ${recipientEmail}", 0, NotificationDeliveryMethod.PUSH); + return submitNotificationRequest(notificationTargetId, "Hello, ${recipientEmail}", 0, NotificationDeliveryMethod.WEB); }); await().atMost(10, TimeUnit.SECONDS).until(request::isDone); NotificationRequest notificationRequest = request.get(); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index d8214a9745..293eb07af9 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.data.util.Pair; +import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration; @@ -92,6 +93,9 @@ import static org.awaitility.Awaitility.await; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest +@TestPropertySource(properties = { + "js.evaluator=local" +}) public class NotificationRuleApiTest extends AbstractNotificationApiTest { @SpyBean @@ -111,10 +115,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_entityActionTrigger() throws Exception { String notificationSubject = "${actionType}: ${entityType} [${entityId}]"; String notificationText = "User: ${originatorUserName}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.GENERAL, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.GENERAL, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification when any device is created, updated or deleted"); + notificationRule.setName("Web notification when any device is created, updated or deleted"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ENTITY_ACTION); @@ -166,10 +170,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { String notificationSubject = "Alarm type: ${alarmType}, status: ${alarmStatus}, " + "severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}"; String notificationText = "Status: ${alarmStatus}, severity: ${alarmSeverity}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification on any alarm"); + notificationRule.setName("Web notification on any alarm"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ALARM); @@ -240,7 +244,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { AlarmSeverity expectedSeverity = AlarmSeverity.CRITICAL; clients.values().forEach(wsClient -> { wsClient.waitForUpdate(true); - Notification updatedNotification = wsClient.getLastDataUpdate().getNotifications().stream().findFirst().get(); + Notification updatedNotification = wsClient.getLastDataUpdate().getUpdate(); assertThat(updatedNotification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + expectedStatus + ", " + "severity: " + expectedSeverity + ", deviceId: " + device.getId()); assertThat(updatedNotification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity); @@ -255,10 +259,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_alarmTrigger_clearRule() throws Exception { String notificationSubject = "${alarmSeverity} alarm '${alarmType}' is ${alarmStatus}"; String notificationText = "${alarmId}"; - NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH); + NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); NotificationRule notificationRule = new NotificationRule(); - notificationRule.setName("Push-notification on any alarm"); + notificationRule.setName("Web notification on any alarm"); notificationRule.setTemplateId(notificationTemplate.getId()); notificationRule.setTriggerType(NotificationRuleTriggerType.ALARM); @@ -311,7 +315,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { getWsClient().registerWaitForUpdate(); alarmSubscriptionService.clearAlarm(tenantId, alarm.getId(), System.currentTimeMillis(), null); getWsClient().waitForUpdate(true); - notification = getWsClient().getLastDataUpdate().getNotifications().iterator().next(); + notification = getWsClient().getLastDataUpdate().getUpdate(); assertThat(notification.getSubject()).isEqualTo("CRITICAL alarm '" + alarmType + "' is CLEARED_UNACK"); assertThat(findNotificationRequests(EntityType.ALARM).getData()).filteredOn(NotificationRequest::isScheduled).isEmpty(); @@ -321,7 +325,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { public void testNotificationRuleProcessing_ruleEngineComponentLifecycleEvent_ruleNodeStartError() { String subject = "Rule Node '${componentName}' in Rule Chain '${ruleChainName}' failed to start"; String text = "The error: ${error}"; - NotificationTemplate template = createNotificationTemplate(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, subject, text, NotificationDeliveryMethod.PUSH); + NotificationTemplate template = createNotificationTemplate(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, subject, text, NotificationDeliveryMethod.WEB); NotificationRule rule = new NotificationRule(); rule.setName("Rule node start-up failures in my rule chain"); @@ -361,7 +365,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { @Test public void testNotificationRuleInfo() throws Exception { - NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL}; + NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL}; NotificationTemplate template = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Subject", "Text", deliveryMethods); NotificationRule rule = new NotificationRule(); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java index 17e8ca1043..67a7fd8bd4 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java @@ -86,9 +86,9 @@ public class NotificationTemplateApiTest extends AbstractNotificationApiTest { @Test public void testTemplatesSearch() throws Exception { - NotificationTemplate alarmNotificationTemplate = createNotificationTemplate(NotificationType.ALARM, "Alarm", "Alarm", NotificationDeliveryMethod.PUSH); - NotificationTemplate generalNotificationTemplate = createNotificationTemplate(NotificationType.GENERAL, "General", "General", NotificationDeliveryMethod.PUSH); - NotificationTemplate entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.PUSH); + NotificationTemplate alarmNotificationTemplate = createNotificationTemplate(NotificationType.ALARM, "Alarm", "Alarm", NotificationDeliveryMethod.WEB); + NotificationTemplate generalNotificationTemplate = createNotificationTemplate(NotificationType.GENERAL, "General", "General", NotificationDeliveryMethod.WEB); + NotificationTemplate entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.WEB); assertThat(findTemplates(NotificationType.ALARM)).extracting(IdBased::getId) .containsOnly(alarmNotificationTemplate.getId()); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java index c781f450cb..af214dbf3d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java @@ -45,7 +45,7 @@ public interface NotificationRequestService { List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId); - void deleteNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); + void deleteNotificationRequest(TenantId tenantId, NotificationRequestId requestId); PageData findScheduledNotificationRequests(PageLink pageLink); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java index 39886500c8..35e74b36e7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java @@ -40,8 +40,6 @@ public interface NotificationService { int countUnreadNotificationsByRecipientId(TenantId tenantId, UserId recipientId); - void updateNotificationsStatusByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status); - boolean deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 4031672c4f..389f16c1ee 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -60,7 +60,7 @@ public interface UserService extends EntityDaoService { PageData findTenantAdmins(TenantId tenantId, PageLink pageLink); - PageData findUsers(TenantId tenantId, PageLink pageLink); + PageData findAllUsers(TenantId tenantId, PageLink pageLink); void deleteTenantAdmins(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index 766a431816..f59ea8d5d0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -30,7 +30,6 @@ public class CacheConstants { public static final String TENANTS_EXIST_CACHE = "tenantsExist"; public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; public static final String NOTIFICATION_RULES_CACHE = "notificationRules"; - public static final String NOTIFICATION_REQUESTS_CACHE = "notificationRequests"; public static final String ASSET_PROFILE_CACHE = "assetProfiles"; public static final String ATTRIBUTES_CACHE = "attributes"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java index ac15bd5d88..c3097d3c49 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/Notification.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.common.data.notification; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; @@ -46,14 +45,4 @@ public class Notification extends BaseData { private NotificationStatus status; - @JsonProperty("text") - public String getProcessedText() { - return NotificationProcessingContext.processTemplate(text, info); - } - - @JsonProperty("subject") - public String getProcessedSubject() { - return NotificationProcessingContext.processTemplate(subject, info); - } - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java index 41522065d0..4a2c4657d5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java @@ -21,7 +21,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum NotificationDeliveryMethod { - PUSH("push-notification"), + WEB("web"), EMAIL("email"), SMS("SMS"), SLACK("Slack"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java index c15d10db93..afcfa278f2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java @@ -33,7 +33,7 @@ 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 org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import java.util.Collections; import java.util.EnumMap; @@ -96,7 +96,7 @@ public class NotificationProcessingContext { public T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map templateContext) { NotificationInfo info = request.getInfo(); - if (info != null && deliveryMethod != NotificationDeliveryMethod.PUSH) { // for push notifications we are processing template from info on each serialization + if (info != null) { templateContext = new HashMap<>(templateContext); templateContext.putAll(info.getTemplateData()); } @@ -108,9 +108,9 @@ public class NotificationProcessingContext { ((HasSubject) template).setSubject(processTemplate(subject, templateContext)); } - if (deliveryMethod == NotificationDeliveryMethod.PUSH) { - PushDeliveryMethodNotificationTemplate pushNotificationTemplate = (PushDeliveryMethodNotificationTemplate) template; - Optional buttonConfig = Optional.ofNullable(pushNotificationTemplate.getAdditionalConfig()) + if (deliveryMethod == NotificationDeliveryMethod.WEB) { + WebDeliveryMethodNotificationTemplate webNotificationTemplate = (WebDeliveryMethodNotificationTemplate) template; + Optional buttonConfig = Optional.ofNullable(webNotificationTemplate.getAdditionalConfig()) .map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject) .map(config -> (ObjectNode) config); if (buttonConfig.isPresent()) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java index 82756d0870..64bba1b9df 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java @@ -15,19 +15,12 @@ */ package org.thingsboard.server.common.data.notification.rule.trigger; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor public enum NotificationRuleTriggerType { - ALARM(true), - ALARM_COMMENT(true), - DEVICE_INACTIVITY(false), - ENTITY_ACTION(false), - RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT(false); - - @Getter - private final boolean updatable; + ALARM, + ALARM_COMMENT, + DEVICE_INACTIVITY, + ENTITY_ACTION, + RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java index 202e329601..0c2441e37d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetType.java @@ -24,7 +24,7 @@ import java.util.Set; @RequiredArgsConstructor public enum NotificationTargetType { - PLATFORM_USERS(Set.of(NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS)), + PLATFORM_USERS(Set.of(NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.EMAIL, NotificationDeliveryMethod.SMS)), SLACK(Set.of(NotificationDeliveryMethod.SLACK)); @Getter diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java index f8598c2a71..86e1ec7f87 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java @@ -20,8 +20,4 @@ public enum UsersFilterType { CUSTOMER_USERS, ALL_USERS, ORIGINATOR_ENTITY_OWNER_USERS - -// USER_GROUP, -// USERS_WITH_ROLE, -// QUERY // ? } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java index fd19afd6f7..ba098304d6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/DeliveryMethodNotificationTemplate.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method") @JsonSubTypes({ - @Type(name = "PUSH", value = PushDeliveryMethodNotificationTemplate.class), + @Type(name = "WEB", value = WebDeliveryMethodNotificationTemplate.class), @Type(name = "EMAIL", value = EmailDeliveryMethodNotificationTemplate.class), @Type(name = "SMS", value = SmsDeliveryMethodNotificationTemplate.class), @Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java similarity index 77% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java index df4ea141cc..3b9b852eff 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/template/WebDeliveryMethodNotificationTemplate.java @@ -26,12 +26,12 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho @NoArgsConstructor @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class PushDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject { +public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject { private String subject; private JsonNode additionalConfig; - public PushDeliveryMethodNotificationTemplate(PushDeliveryMethodNotificationTemplate other) { + public WebDeliveryMethodNotificationTemplate(WebDeliveryMethodNotificationTemplate other) { super(other); this.subject = other.subject; this.additionalConfig = other.additionalConfig; @@ -39,12 +39,12 @@ public class PushDeliveryMethodNotificationTemplate extends DeliveryMethodNotifi @Override public NotificationDeliveryMethod getMethod() { - return NotificationDeliveryMethod.PUSH; + return NotificationDeliveryMethod.WEB; } @Override - public PushDeliveryMethodNotificationTemplate copy() { - return new PushDeliveryMethodNotificationTemplate(this); + public WebDeliveryMethodNotificationTemplate copy() { + return new WebDeliveryMethodNotificationTemplate(this); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index f891e1b118..e951a75c7c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -30,10 +30,7 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStats; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.entity.EntityDaoService; -import org.thingsboard.server.dao.notification.cache.NotificationRequestCacheKey; -import org.thingsboard.server.dao.notification.cache.NotificationRequestCacheValue; import org.thingsboard.server.dao.service.DataValidator; import java.util.List; @@ -42,7 +39,7 @@ import java.util.Optional; @Service @Slf4j @RequiredArgsConstructor -public class DefaultNotificationRequestService extends AbstractCachedEntityService implements NotificationRequestService, EntityDaoService { +public class DefaultNotificationRequestService implements NotificationRequestService, EntityDaoService { private final NotificationRequestDao notificationRequestDao; @@ -51,14 +48,7 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi @Override public NotificationRequest saveNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { notificationRequestValidator.validate(notificationRequest, NotificationRequest::getTenantId); - try { - notificationRequest = notificationRequestDao.save(tenantId, notificationRequest); - publishEvictEvent(notificationRequest); - } catch (Exception e) { - handleEvictEvent(notificationRequest); - throw e; - } - return notificationRequest; + return notificationRequestDao.save(tenantId, notificationRequest); } @Override @@ -88,21 +78,13 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi @Override public List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - NotificationRequestCacheKey cacheKey = NotificationRequestCacheKey.builder() - .originatorEntityId(originatorEntityId) - .ruleId(ruleId) - .build(); - return cache.getAndPutInTransaction(cacheKey, () -> NotificationRequestCacheValue.builder() - .notificationRequests(notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId)) - .build(), false) - .getNotificationRequests(); + return notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId); } // ON DELETE CASCADE is used: notifications for request are deleted as well @Override - public void deleteNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) { - publishEvictEvent(notificationRequest); - notificationRequestDao.removeById(tenantId, notificationRequest.getUuidId()); + public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId requestId) { + notificationRequestDao.removeById(tenantId, requestId.getId()); } @Override @@ -120,17 +102,6 @@ public class DefaultNotificationRequestService extends AbstractCachedEntityServi notificationRequestDao.removeByTenantId(tenantId); } - @Override - public void handleEvictEvent(NotificationRequest notificationRequest) { - if (notificationRequest.getRuleId() == null) return; - - NotificationRequestCacheKey cacheKey = NotificationRequestCacheKey.builder() - .originatorEntityId(notificationRequest.getOriginatorEntityId()) - .ruleId(notificationRequest.getRuleId()) - .build(); - cache.evict(cacheKey); - } - @Override public Optional> findEntity(TenantId tenantId, EntityId entityId) { return Optional.ofNullable(findNotificationRequestById(tenantId, new NotificationRequestId(entityId.getId()))); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java index 78c964c4b8..cf34f6fcfb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.NotificationId; -import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; @@ -77,11 +76,6 @@ public class DefaultNotificationService implements NotificationService { return notificationDao.countUnreadByRecipientId(tenantId, recipientId); } - @Override - public void updateNotificationsStatusByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status) { - notificationDao.updateStatusesByRequestId(tenantId, requestId, status); - } - @Override public boolean deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId) { return notificationDao.deleteByIdAndRecipientId(tenantId, recipientId, notificationId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java index bdf802dea0..e1089b703a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java @@ -121,7 +121,7 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { return userService.findUsersByTenantId(tenantId, pageLink); } else { - return userService.findUsers(TenantId.SYS_TENANT_ID, pageLink); + return userService.findAllUsers(TenantId.SYS_TENANT_ID, pageLink); } } case ORIGINATOR_ENTITY_OWNER_USERS: { diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java index 57e5c410de..1ced714bce 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java @@ -37,8 +37,6 @@ public interface NotificationDao extends Dao { PageData findByRequestId(TenantId tenantId, NotificationRequestId notificationRequestId, PageLink pageLink); - void updateStatusesByRequestId(TenantId tenantId, NotificationRequestId requestId, NotificationStatus status); - boolean deleteByIdAndRecipientId(TenantId tenantId, UserId recipientId, NotificationId notificationId); int updateStatusByRecipientId(TenantId tenantId, UserId recipientId, NotificationStatus status); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java deleted file mode 100644 index 403e192fbb..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheKey.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 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.cache; - -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.NotificationRuleId; - -import java.io.Serializable; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class NotificationRequestCacheKey implements Serializable { - - private static final long serialVersionUID = 59871139005482170L; - - private EntityId originatorEntityId; - private NotificationRuleId ruleId; - - @Override - public String toString() { - return ruleId + "_" + originatorEntityId; - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java deleted file mode 100644 index cdd21720ca..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCacheValue.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * 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.cache; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.notification.NotificationRequest; -import org.thingsboard.server.common.data.notification.rule.NotificationRule; - -import java.io.Serializable; -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class NotificationRequestCacheValue implements Serializable { - - private static final long serialVersionUID = 950211234585105415L; - - private List notificationRequests; - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java deleted file mode 100644 index 2b2dc91fc9..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestCaffeineCache.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 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.cache; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cache.CacheManager; -import org.springframework.stereotype.Service; -import org.thingsboard.server.cache.CaffeineTbTransactionalCache; -import org.thingsboard.server.common.data.CacheConstants; - -@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) -@Service -public class NotificationRequestCaffeineCache extends CaffeineTbTransactionalCache { - - public NotificationRequestCaffeineCache(CacheManager cacheManager) { - super(cacheManager, CacheConstants.NOTIFICATION_REQUESTS_CACHE); - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java deleted file mode 100644 index 0da04c15db..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/cache/NotificationRequestRedisCache.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * 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.cache; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.stereotype.Service; -import org.thingsboard.server.cache.CacheSpecsMap; -import org.thingsboard.server.cache.RedisTbTransactionalCache; -import org.thingsboard.server.cache.TBRedisCacheConfiguration; -import org.thingsboard.server.cache.TbFSTRedisSerializer; -import org.thingsboard.server.common.data.CacheConstants; - -@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") -@Service -public class NotificationRequestRedisCache extends RedisTbTransactionalCache { - - public NotificationRequestRedisCache(CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory, TBRedisCacheConfiguration configuration) { - super(CacheConstants.NOTIFICATION_REQUESTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java index 0f1f4d9722..d998c355c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java @@ -88,11 +88,6 @@ public class JpaNotificationDao extends JpaAbstractDao findByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityTypeAndOriginatorEntityId(ruleId.getId(), originatorEntityId.getEntityType(), originatorEntityId.getId())); + return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(ruleId.getId(), originatorEntityId.getId(), originatorEntityId.getEntityType())); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java index 1da2ebfcde..ebeb2a7a1b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java @@ -48,13 +48,6 @@ public interface NotificationRepository extends JpaRepository findByRequestId(UUID requestId, Pageable pageable); - @Modifying - @Transactional - @Query("UPDATE NotificationEntity n SET n.status = :status " + - "WHERE n.requestId = :requestId AND n.status <> :status") - int updateStatusesByRequestId(@Param("requestId") UUID requestId, - @Param("status") NotificationStatus status); - @Transactional int deleteByIdAndRecipientId(UUID id, UUID recipientId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java index 611b56ee77..d28b0dc95b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java @@ -54,7 +54,7 @@ public interface NotificationRequestRepository extends JpaRepository findAllIdsByStatusAndRuleId(@Param("status") NotificationRequestStatus status, @Param("ruleId") UUID ruleId); - List findAllByRuleIdAndOriginatorEntityTypeAndOriginatorEntityId(UUID ruleId, EntityType originatorEntityType, UUID originatorEntityId); + List findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(UUID ruleId, UUID originatorEntityId, EntityType originatorEntityType); Page findAllByStatus(NotificationRequestStatus status, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index c59efe69ff..4b55cb099b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -250,7 +250,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } @Override - public PageData findUsers(TenantId tenantId, PageLink pageLink) { + public PageData findAllUsers(TenantId tenantId, PageLink pageLink) { return userDao.findAll(tenantId, pageLink); } diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index fb6940e2cb..34359302ad 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -97,8 +97,11 @@ CREATE INDEX IF NOT EXISTS idx_notification_template_tenant_id_created_time ON n CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_created_time ON notification_rule(tenant_id, created_time DESC); CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_originator_type_created_time ON notification_request(tenant_id, originator_entity_type, created_time DESC); + CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id); + CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_request(status); CREATE INDEX IF NOT EXISTS idx_notification_id_recipient_id ON notification(id, recipient_id); + CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_status_created_time ON notification(recipient_id, status, created_time DESC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index f2518ecdcf..17a989a53e 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -846,7 +846,6 @@ CREATE TABLE IF NOT EXISTS notification ( subject VARCHAR(255), text VARCHAR(1000) NOT NULL, additional_config VARCHAR(1000), - info VARCHAR(1000), status VARCHAR(32) ) PARTITION BY RANGE (created_time); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java index d39897a5d3..eccc4f1423 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java @@ -25,8 +25,6 @@ public interface NotificationCenter { NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); - NotificationRequest updateNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); - void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId); void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text);