Search in sources :

Example 1 with HEADER_SOURCE

use of org.openremote.model.notification.Notification.HEADER_SOURCE in project openremote by openremote.

the class NotificationService method configure.

@Override
public void configure() throws Exception {
    from(NOTIFICATION_QUEUE).routeId("NotificationQueueProcessor").doTry().process(exchange -> {
        Notification notification = exchange.getIn().getBody(Notification.class);
        if (notification == null) {
            throw new NotificationProcessingException(MISSING_NOTIFICATION, "Notification must be set");
        }
        LOG.finest("Processing: " + notification.getName());
        if (notification.getMessage() == null) {
            throw new NotificationProcessingException(MISSING_MESSAGE, "Notification message must be set");
        }
        Notification.Source source = exchange.getIn().getHeader(HEADER_SOURCE, () -> null, Notification.Source.class);
        if (source == null) {
            throw new NotificationProcessingException(MISSING_SOURCE);
        }
        // Validate handler and message
        NotificationHandler handler = notificationHandlerMap.get(notification.getMessage().getType());
        if (handler == null) {
            throw new NotificationProcessingException(UNSUPPORTED_MESSAGE_TYPE, "No handler for message type: " + notification.getMessage().getType());
        }
        if (!handler.isValid()) {
            throw new NotificationProcessingException(NOTIFICATION_HANDLER_CONFIG_ERROR, "Handler is not valid: " + handler.getTypeName());
        }
        if (!handler.isMessageValid(notification.getMessage())) {
            throw new NotificationProcessingException(INVALID_MESSAGE);
        }
        // Validate access and map targets to handler compatible targets
        String realm = null;
        String userId = null;
        String assetId = null;
        AtomicReference<String> sourceId = new AtomicReference<>("");
        boolean isSuperUser = false;
        boolean isRestrictedUser = false;
        switch(source) {
            case INTERNAL:
                isSuperUser = true;
                break;
            case CLIENT:
                AuthContext authContext = exchange.getIn().getHeader(Constants.AUTH_CONTEXT, AuthContext.class);
                if (authContext == null) {
                    // Anonymous clients cannot send notifications
                    throw new NotificationProcessingException(INSUFFICIENT_ACCESS);
                }
                realm = authContext.getAuthenticatedRealm();
                userId = authContext.getUserId();
                sourceId.set(userId);
                isSuperUser = authContext.isSuperUser();
                isRestrictedUser = identityService.getIdentityProvider().isRestrictedUser(authContext);
                break;
            case GLOBAL_RULESET:
                isSuperUser = true;
                break;
            case TENANT_RULESET:
                realm = exchange.getIn().getHeader(Notification.HEADER_SOURCE_ID, String.class);
                sourceId.set(realm);
                break;
            case ASSET_RULESET:
                assetId = exchange.getIn().getHeader(Notification.HEADER_SOURCE_ID, String.class);
                sourceId.set(assetId);
                Asset<?> asset = assetStorageService.find(assetId, false);
                realm = asset.getRealm();
                break;
        }
        LOG.info("Sending " + notification.getMessage().getType() + " notification '" + notification.getName() + "': '" + source + ":" + sourceId.get() + "' -> " + notification.getTargets());
        // Check access permissions
        checkAccess(source, sourceId.get(), notification.getTargets(), realm, userId, isSuperUser, isRestrictedUser, assetId);
        // Get the list of notification targets
        List<Notification.Target> mappedTargetsList = handler.getTargets(source, sourceId.get(), notification.getTargets(), notification.getMessage());
        if (mappedTargetsList == null || mappedTargetsList.isEmpty()) {
            throw new NotificationProcessingException(MISSING_TARGETS, "Notification targets must be set");
        }
        // Filter targets based on repeat frequency
        if (!TextUtil.isNullOrEmpty(notification.getName()) && (!TextUtil.isNullOrEmpty(notification.getRepeatInterval()) || notification.getRepeatFrequency() != null)) {
            mappedTargetsList = mappedTargetsList.stream().filter(target -> okToSendNotification(source, sourceId.get(), target, notification)).collect(Collectors.toList());
        }
        // Send message to each applicable target
        AtomicBoolean success = new AtomicBoolean(true);
        mappedTargetsList.forEach(target -> {
            boolean targetSuccess = persistenceService.doReturningTransaction(em -> {
                // commit the notification first to get the ID
                SentNotification sentNotification = new SentNotification().setName(notification.getName()).setType(notification.getMessage().getType()).setSource(source).setSourceId(sourceId.get()).setTarget(target.getType()).setTargetId(target.getId()).setMessage(notification.getMessage()).setSentOn(Date.from(timerService.getNow()));
                sentNotification = em.merge(sentNotification);
                long id = sentNotification.getId();
                try {
                    NotificationSendResult result = handler.sendMessage(id, source, sourceId.get(), target, notification.getMessage());
                    if (result.isSuccess()) {
                        LOG.info("Notification sent '" + id + "': " + target);
                    } else {
                        LOG.warning("Notification failed '" + id + "': " + target + ", reason=" + result.getMessage());
                        sentNotification.setError(TextUtil.isNullOrEmpty(result.getMessage()) ? "Unknown error" : result.getMessage());
                    }
                    // Merge the sent notification again with the message included just in case the handler modified the message
                    sentNotification.setMessage(notification.getMessage());
                    em.merge(sentNotification);
                } catch (Exception e) {
                    LOG.log(Level.SEVERE, "Notification handler threw an exception whilst sending notification '" + id + "'", e);
                    sentNotification.setError(TextUtil.isNullOrEmpty(e.getMessage()) ? "Unknown error" : e.getMessage());
                    em.merge(sentNotification);
                }
                return sentNotification.getError() == null;
            });
            if (!targetSuccess) {
                success.set(false);
            }
        });
        exchange.getOut().setBody(success.get());
    }).endDoTry().doCatch(NotificationProcessingException.class).process(handleNotificationProcessingException(LOG));
}
Also used : AssetStorageService(org.openremote.manager.asset.AssetStorageService) IntStream(java.util.stream.IntStream) Source(org.openremote.model.notification.Notification.Source) java.util(java.util) AuthContext(org.openremote.container.security.AuthContext) Protocol(org.openremote.model.asset.agent.Protocol) SentNotification(org.openremote.model.notification.SentNotification) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Exchange(org.apache.camel.Exchange) TypedQuery(javax.persistence.TypedQuery) AtomicReference(java.util.concurrent.atomic.AtomicReference) Level(java.util.logging.Level) Processor(org.apache.camel.Processor) Notification(org.openremote.model.notification.Notification) UserQuery(org.openremote.model.query.UserQuery) PersistenceService(org.openremote.container.persistence.PersistenceService) TextUtil(org.openremote.model.util.TextUtil) ManagerWebService(org.openremote.manager.web.ManagerWebService) NotificationSendResult(org.openremote.model.notification.NotificationSendResult) MessageBrokerService(org.openremote.container.message.MessageBrokerService) ManagerIdentityService(org.openremote.manager.security.ManagerIdentityService) Asset(org.openremote.model.asset.Asset) ContainerService(org.openremote.model.ContainerService) Constants(org.openremote.model.Constants) Instant(java.time.Instant) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) Container(org.openremote.model.Container) Reason(org.openremote.manager.notification.NotificationProcessingException.Reason) HEADER_SOURCE(org.openremote.model.notification.Notification.HEADER_SOURCE) Query(javax.persistence.Query) ChronoUnit(java.time.temporal.ChronoUnit) RouteBuilder(org.apache.camel.builder.RouteBuilder) TimerService(org.openremote.container.timer.TimerService) RepeatFrequency(org.openremote.model.notification.RepeatFrequency) TimeUtil(org.openremote.model.util.TimeUtil) AuthContext(org.openremote.container.security.AuthContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) NotificationSendResult(org.openremote.model.notification.NotificationSendResult) SentNotification(org.openremote.model.notification.SentNotification) Notification(org.openremote.model.notification.Notification) Source(org.openremote.model.notification.Notification.Source) SentNotification(org.openremote.model.notification.SentNotification) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Asset(org.openremote.model.asset.Asset)

Aggregations

Instant (java.time.Instant)1 ChronoUnit (java.time.temporal.ChronoUnit)1 java.util (java.util)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Level (java.util.logging.Level)1 Logger (java.util.logging.Logger)1 Collectors (java.util.stream.Collectors)1 IntStream (java.util.stream.IntStream)1 Query (javax.persistence.Query)1 TypedQuery (javax.persistence.TypedQuery)1 Exchange (org.apache.camel.Exchange)1 Processor (org.apache.camel.Processor)1 RouteBuilder (org.apache.camel.builder.RouteBuilder)1 MessageBrokerService (org.openremote.container.message.MessageBrokerService)1 PersistenceService (org.openremote.container.persistence.PersistenceService)1 AuthContext (org.openremote.container.security.AuthContext)1 TimerService (org.openremote.container.timer.TimerService)1 AssetStorageService (org.openremote.manager.asset.AssetStorageService)1 Reason (org.openremote.manager.notification.NotificationProcessingException.Reason)1