Search in sources :

Example 1 with ServerSideActionService

use of won.owner.web.service.ServerSideActionService in project webofneeds by researchstudio-sat.

the class WonWebSocketHandler method process.

/**
 * Sends a message coming from the WoN node to the client.
 */
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public WonMessage process(final WonMessage wonMessage) {
    try {
        logger.debug("processing message {} incoming from node", wonMessage.getMessageURI());
        String wonMessageJsonLdString = WonMessageEncoder.encodeAsJsonLd(wonMessage);
        WebSocketMessage<String> webSocketMessage = new TextMessage(wonMessageJsonLdString);
        logger.debug("determining which owned atom is to be informed of message {} ", wonMessage.getMessageURI());
        URI atomUri = getOwnedAtomURIForMessageFromNode(wonMessage);
        logger.debug("obtaining WebSocketSessions for message {} ", wonMessage.getMessageURI());
        Set<WebSocketSession> webSocketSessions = webSocketSessionService.getWebSocketSessions(atomUri);
        Optional<User> userOpt = webSocketSessions == null ? Optional.empty() : webSocketSessions.stream().filter(s -> s.isOpen()).findFirst().map(s -> getUserForSession(s));
        logger.debug("found {} sessions for message {} ", webSocketSessions.size(), wonMessage.getMessageURI());
        logger.debug("found user for message {} via session: {} ", wonMessage.getMessageURI(), userOpt.isPresent());
        if (!userOpt.isPresent()) {
            userOpt = Optional.ofNullable(userRepository.findByAtomUri(atomUri));
        }
        logger.debug("found user for message {} atom uri: {} ", wonMessage.getMessageURI(), userOpt.isPresent());
        // it's quite possible that we don't find the user object this way.
        User user = userOpt.orElse(null);
        // Methods below can handle that.
        logger.debug("updating user-atom association for message {}, user has been found:{} ", wonMessage.getMessageURI(), userOpt.isPresent());
        userAtomService.updateUserAtomAssociation(wonMessage, user);
        logger.debug("trying to find WebSocketSessions for message{}, atom {}, user has been found:{}", new Object[] { wonMessage.getMessageURI(), atomUri, userOpt.isPresent() });
        webSocketSessions = webSocketSessionService.findWebSocketSessionsForAtomAndUser(atomUri, user);
        // check if we can deliver the message. If not, send email.
        if (webSocketSessions.size() == 0) {
            if (logger.isDebugEnabled()) {
                logger.debug("cannot deliver message {}: no websocket session found. Trying to send message by email.", wonMessage.toShortStringForDebug());
            }
            notifyUserOnDifferentChannel(wonMessage, atomUri, user);
            return wonMessage;
        }
        // we can send it - pre-cache the delivery chain:
        logger.debug("put message {} into cache before sending on websocket", wonMessage.getMessageURI());
        eagerlyCachePopulatingProcessor.process(wonMessage);
        // send to owner webapp
        int successfullySent = 0;
        for (WebSocketSession session : webSocketSessions) {
            logger.debug("sending message {} via websocket session", wonMessage.getMessageURI());
            successfullySent += sendMessageForSession(wonMessage, webSocketMessage, session, atomUri, user) ? 1 : 0;
        }
        logger.debug("sent message {} via {} websocket sessions", wonMessage.getMessageURI(), successfullySent);
        if (successfullySent == 0) {
            // we did not manage to send the message via the websocket, send it by email.
            if (logger.isDebugEnabled()) {
                logger.debug("cannot deliver message {}: none of the associated websocket sessions worked. Trying to send message by webpush and email.", wonMessage.toShortStringForDebug());
            }
            // TODO: ideally in this case
            // 1. collect multiple events occurring in close succession
            // 2. try to push
            // 3. email only if push was not successful
            notifyUserOnDifferentChannel(wonMessage, atomUri, user);
        } else {
            // Always send possible pushNotifications:
            // - maybe session is active -> message was send, but Tab is not focused
            // - Browser is running in background -> user needs to get push notification
            Optional<URI> connectionURI = WonLinkedDataUtils.getConnectionURIForIncomingMessage(wonMessage, linkedDataSource);
            if (connectionURI.isPresent()) {
                logger.debug("notifying user per web push for message {}", wonMessage.getMessageURI());
                UserAtom userAtom = getAtomOfUser(user, atomUri);
                if (userAtom == null) {
                    userOpt = Optional.ofNullable(userRepository.findByAtomUri(atomUri));
                    user = userOpt.orElse(null);
                }
                notifyPerPush(user, atomUri, wonMessage, connectionURI.get());
            }
            logger.debug("cannot notify user: cannot determine connection URI");
        }
        return wonMessage;
    } finally {
        // in any case, let the serversideactionservice do its work, if there is any to
        // do:
        logger.debug("processing server side actions for message {} if any are registered", wonMessage.getMessageURI());
        serverSideActionService.process(wonMessage);
    }
}
Also used : StringUtils(org.apache.commons.lang.StringUtils) OwnerApplicationService(won.owner.service.impl.OwnerApplicationService) LoggerFactory(org.slf4j.LoggerFactory) SessionRepository(org.springframework.session.SessionRepository) Autowired(org.springframework.beans.factory.annotation.Autowired) UserRepository(won.owner.repository.UserRepository) CloseStatus(org.springframework.web.socket.CloseStatus) LoggingUtils(won.protocol.util.LoggingUtils) TextMessage(org.springframework.web.socket.TextMessage) Duration(java.time.Duration) Map(java.util.Map) URI(java.net.URI) WonMessageEncoder(won.protocol.message.WonMessageEncoder) WonLinkedDataUtils(won.protocol.util.linkeddata.WonLinkedDataUtils) WonMessageType(won.protocol.message.WonMessageType) MethodHandles(java.lang.invoke.MethodHandles) Set(java.util.Set) Collectors(java.util.stream.Collectors) StandardCharsets(java.nio.charset.StandardCharsets) WonRdfUtils(won.protocol.util.WonRdfUtils) UncheckedIOException(java.io.UncheckedIOException) Base64(java.util.Base64) Principal(java.security.Principal) DisposableBean(org.springframework.beans.factory.DisposableBean) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ServerSideActionService(won.owner.web.service.ServerSideActionService) Optional(java.util.Optional) MailException(org.springframework.mail.MailException) Authentication(org.springframework.security.core.Authentication) Isolation(org.springframework.transaction.annotation.Isolation) LinkedDataSource(won.protocol.util.linkeddata.LinkedDataSource) UserAtom(won.owner.model.UserAtom) AuthenticationThreadLocal(won.protocol.util.AuthenticationThreadLocal) ConnectionState(won.protocol.model.ConnectionState) MessageDigest(java.security.MessageDigest) WonMessageDecoder(won.protocol.message.WonMessageDecoder) WebSocketSession(org.springframework.web.socket.WebSocketSession) InitializingBean(org.springframework.beans.factory.InitializingBean) WonMessage(won.protocol.message.WonMessage) MessageFormat(java.text.MessageFormat) TextWebSocketHandler(org.springframework.web.socket.handler.TextWebSocketHandler) Propagation(org.springframework.transaction.annotation.Propagation) WonMessageProcessor(won.protocol.message.processor.WonMessageProcessor) ObjectNode(org.codehaus.jackson.node.ObjectNode) WonOwnerPushSender(won.owner.web.WonOwnerPushSender) Order(org.springframework.core.annotation.Order) Logger(org.slf4j.Logger) WebSocketMessage(org.springframework.web.socket.WebSocketMessage) WonOwnerMailSender(won.owner.web.WonOwnerMailSender) Session(org.springframework.session.Session) IOException(java.io.IOException) KeystoreEnabledUserDetails(won.owner.service.impl.KeystoreEnabledUserDetails) User(won.owner.model.User) URIService(won.owner.service.impl.URIService) BatchingConsumer(won.utils.batch.BatchingConsumer) UserAtomService(won.owner.web.service.UserAtomService) ObjectMapper(org.codehaus.jackson.map.ObjectMapper) Transactional(org.springframework.transaction.annotation.Transactional) User(won.owner.model.User) UserAtom(won.owner.model.UserAtom) URI(java.net.URI) TextMessage(org.springframework.web.socket.TextMessage) WebSocketSession(org.springframework.web.socket.WebSocketSession) Transactional(org.springframework.transaction.annotation.Transactional)

Aggregations

IOException (java.io.IOException)1 UncheckedIOException (java.io.UncheckedIOException)1 MethodHandles (java.lang.invoke.MethodHandles)1 URI (java.net.URI)1 StandardCharsets (java.nio.charset.StandardCharsets)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 Principal (java.security.Principal)1 MessageFormat (java.text.MessageFormat)1 Duration (java.time.Duration)1 Base64 (java.util.Base64)1 Map (java.util.Map)1 Optional (java.util.Optional)1 Set (java.util.Set)1 Collectors (java.util.stream.Collectors)1 StringUtils (org.apache.commons.lang.StringUtils)1 ObjectMapper (org.codehaus.jackson.map.ObjectMapper)1 ObjectNode (org.codehaus.jackson.node.ObjectNode)1 Logger (org.slf4j.Logger)1 LoggerFactory (org.slf4j.LoggerFactory)1