Package com.streamreduce.core.service

Source Code of com.streamreduce.core.service.MessageServiceImpl

/*
* Copyright 2012 Nodeable Inc
*
*    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 com.streamreduce.core.service;

import com.streamreduce.ConnectionNotFoundException;
import com.streamreduce.OutboundStorageException;
import com.streamreduce.connections.ConnectionProvider;
import com.streamreduce.connections.ConnectionProviderFactory;
import com.streamreduce.core.dao.SobaMessageDAO;
import com.streamreduce.core.event.EventId;
import com.streamreduce.core.model.Account;
import com.streamreduce.core.model.Connection;
import com.streamreduce.core.model.Event;
import com.streamreduce.core.model.InventoryItem;
import com.streamreduce.core.model.SobaObject;
import com.streamreduce.core.model.User;
import com.streamreduce.core.model.messages.MessageComment;
import com.streamreduce.core.model.messages.MessageType;
import com.streamreduce.core.model.messages.SobaMessage;
import com.streamreduce.core.model.messages.details.SobaMessageDetails;
import com.streamreduce.core.service.exception.AccountNotFoundException;
import com.streamreduce.core.service.exception.MessageNotFoundException;
import com.streamreduce.core.service.exception.TargetNotFoundException;
import com.streamreduce.core.transformer.MessageTransformerResult;
import com.streamreduce.core.transformer.SobaMessageTransformerFactory;
import com.streamreduce.util.HashtagUtil;
import com.streamreduce.util.MessageUtils;

import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.annotation.Nullable;
import javax.annotation.Resource;

import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("messageService")
public class MessageServiceImpl extends AbstractService implements MessageService {

    @Autowired
    private SobaMessageDAO sobaMessageDAO;
    @Autowired
    private ConnectionProviderFactory connectionProviderFactory;
    @Autowired
    private OutboundStorageService outboundStorageService;
    @Autowired
    private UserService userService;
    @Autowired
    private ConnectionService connectionService;
    @Autowired
    private EventService eventService;
    @Autowired
    private EmailService emailService;

    @Resource(name = "messageProperties")
    public Properties messageProperties;

    @Override
    public List<SobaMessage> getAllMessages(User currentUser, Long after, Long before, int limit, boolean ascending, String search, List<String> hashTags, String sender, boolean excludeNodebellies) {
        return sobaMessageDAO.getMessagesFromInbox(currentUser, after, before, limit, ascending, search, HashtagUtil.normalizeTags(hashTags), sender, excludeNodebellies);
    }

    @Override
    public SobaMessage getMessage(Account account, ObjectId messageId) throws MessageNotFoundException {
        SobaMessage message = sobaMessageDAO.getFromInbox(account, messageId);
        if (message == null) {
            throw new MessageNotFoundException(messageId.toString());
        }
        return message;
    }

    // for all inboxes, will create mult
    @SuppressWarnings("rawtypes")
    @Override
    public void sendNodebellyGlobalMessage(Event event, SobaObject sender, Connection connection,
                                           Long dateGenerated, MessageType type, Set<String> hashtags) {
        this.createMessage(event, sender, connection, dateGenerated, type, hashtags, null);
    }

    // for a certain account
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public SobaMessage sendNodeableAccountMessage(Event event, Account account, Set<String> hashtags) {

        User sender = userService.getSystemUser();
        // this enables us to save in a target account rather than use the senders account
        sender.setAccount(account);
        return sendAccountMessage(
                event,
                sender, // sent from nodebelly
                null, // no connectionId right now
                new Date().getTime(),
                MessageType.SYSTEM,
                hashtags,
                null
        );
    }

    @Override
    public SobaMessage sendConnectionMessage(Event event, Connection connection) {
        return sendAccountMessage(
                event,
                connection,
                connection, // happens to be the same as sender
                new Date().getTime(),
                MessageType.CONNECTION,
                connection.getHashtags(),
                null
        );
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public SobaMessage sendInventoryMessage(Event event, InventoryItem inventoryItem) {
        return sendAccountMessage(event,
                inventoryItem,
                inventoryItem.getConnection(),
                new Date().getTime(),
                MessageType.INVENTORY_ITEM,
                inventoryItem.getHashtags(),
                null
        );
    }

    @Override
    public SobaMessage sendActivityMessage(Event event, Connection connection, Long dateGenerated, SobaMessageDetails details) {
        return sendAccountMessage(
                event,
                connection,
                connection, // happens to be the same as sender
                dateGenerated,
                MessageType.ACTIVITY,
                connection.getHashtags(),
                details
        );
    }

    @Override
    public SobaMessage sendGatewayMessage(Event event, Connection connection, Long dateGenerated) {
        return sendAccountMessage(
                event,
                connection,
                connection, // happens to be the same as sender
                dateGenerated,
                MessageType.GATEWAY,
                connection.getHashtags(),
                null
        );
    }

    @Override
    public SobaMessage sendGatewayMessage(Event event, InventoryItem inventoryItem, Long dateGenerated) {
        return sendAccountMessage(
                event,
                inventoryItem,
                inventoryItem.getConnection(),
                dateGenerated,
                MessageType.GATEWAY,
                inventoryItem.getHashtags(),
                null
        );
    }

    @SuppressWarnings("rawtypes")
    @Override
    public SobaMessage sendAccountMessage(Event event, SobaObject sender, Connection connection,
                                          Long dateGenerated, MessageType type, Set<String> hashtags, SobaMessageDetails details) {
        return createMessage(event, sender, connection, dateGenerated, type, hashtags, details);
    }

    @Override
    public SobaMessage sendNodebellyInsightMessage(Event event, Long dateGenerated, Set<String> hashtags) {
        if (event == null || dateGenerated == null) {
            throw new IllegalArgumentException("event and dateGenerated must be non-null");
        }
        hashtags = hashtags == null ? new HashSet<String>() : hashtags;

        SobaMessage sobaMessage = null;

        try {
            // if this is the sender, should we override the ownerId? how?
            User nodebelly = userService.getSuperUser();

            // if this is null, it's a global metric so only persist the message to the Nodeable account
            if (event.getAccountId() != null) {
                Account account = userService.getAccount(event.getAccountId());

                // send an email if these are your first insights
                // SOBA-1600
                if (!account.getConfigValue(Account.ConfigKey.RECIEVED_INSIGHTS)) {
                    userService.handleInitialInsightForAccount(account);
                }

                // trickery to send from Nodebelly to a certain account
                // DO NOT PERSIST THIS!!!!!
                // also note how this is set last so the account references above are still valid to the "real" account
                nodebelly.setAccount(account);
            }

            Map<String, Object> meta = event.getMetadata();
            String objectType = (String) meta.get("targetType");
            String providerTypeId = (String) meta.get("targetProviderId");

            // filter out inventory count messages, since they are redundant with connection counts
            String metricName = (String) meta.get("name");
            if (metricName.startsWith("INVENTORY_ITEM_COUNT.")) {
                return null;
            }

            // get the connection where applicable
            Connection connection = null;
            try {
                ObjectId connectionId = null;
                // ugh
                if (objectType.contains("Connection")) {
                    connectionId = event.getTargetId();
                } else if (objectType.contains("InventoryItem")) {
                    connectionId = new ObjectId(meta.get("targetConnectionId").toString());
                }
                connection = connectionService.getConnection(connectionId);
            } catch (ConnectionNotFoundException e) {
                logger.error("Invalid connection Id, can not send Nodebelly Message" + e.getMessage());
            }

            // custom tags
            hashtags.add("#insight");
            if (providerTypeId != null) {
                hashtags.add(HashtagUtil.normalizeTag(providerTypeId)); // ie, aws, github, jira (this should be what we currently aggregate on
            }
            hashtags.add(HashtagUtil.toNodebellyTag(event.getEventId())); // based suffix of eventId

            sobaMessage = this.createMessage(event, nodebelly, connection, dateGenerated, MessageType.NODEBELLY, hashtags, null);
        } catch (AccountNotFoundException e) {
            logger.error(e.getMessage());
        }
        return sobaMessage;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public SobaMessage sendUserMessage(Event event, User sender, String message) throws TargetNotFoundException {
        // Not sure if this is possible but since the EventService can return null for created events and we want to
        // avoid NPEs, let's be safe.
        if (event == null) {
            return null;
        }

        MessageUtils.ParsedMessage parsedMessage = MessageUtils.parseMessage(message);
        Set<String> hashtags = parsedMessage.getTags();
        // this is now a conversation (even if with no one), so add that tag
        hashtags.add("#conversation");

        SobaMessage sobaMessage = createMessage(event,
                sender,
                null,
                new Date().getTime(),
                MessageType.USER,
                hashtags,
                null);
        emailService.sendUserMessageAddedEmail(sender, sobaMessage);
        return sobaMessage;
    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    protected SobaMessage createMessage(Event event, SobaObject sender,
                                        Connection connection, Long dateGenerated,
                                        MessageType type, Set<String> hashtags, @Nullable SobaMessageDetails details) {
        // Anytime the event is null, we do not want to send the requested message
        if (event == null) {
            return null;
        }

        // convert to a more user friendly string
        // accept messageDetails (if any) so we can append info if needed
        MessageTransformerResult messageTransformerResult =
                SobaMessageTransformerFactory.transformMessage(event, type, details, messageProperties);

        // plain text
        String transformedMessage = messageTransformerResult.getTransformedMessage();
        // embed the rich formatted message in the soba object
        SobaMessageDetails sobaMessageDetails = messageTransformerResult.getMessageDetails();

        SobaMessage message = new SobaMessage.Builder()
                .sender(sender)
                .dateGenerated(dateGenerated)
                .type(type)
                .connection(connection)
                .transformedMessage(transformedMessage)
                .hashtags(hashtags)
                .details(sobaMessageDetails)
                .build();

        // save to inbox(es)
        saveMessage(sender, message);

        // Fire the event that a message has been created
        Map<String, Object> eventMetadata = new HashMap<>();

        // Message event metadata
        eventMetadata.put("messageEventId", event.getId());
        eventMetadata.put("messageEventAccountId", event.getAccountId());
        eventMetadata.put("messageEventTargetId", event.getTargetId());
        eventMetadata.put("messageEventTargetType", event.getMetadata().get("targetType"));
        eventMetadata.put("messageEventUserId", event.getUserId());
        eventMetadata.put("messageEventEventId", event.getEventId());

        // General metadata
        eventMetadata.put("messageDateGenerated", dateGenerated);
        eventMetadata.put("messageType", type);
        eventMetadata.put("messageHashtags", hashtags);
        eventMetadata.put("messagePlainContent", transformedMessage);

        // Sender metadata
        eventMetadata.put("messageSenderId", sender.getId());
        eventMetadata.put("messageSenderType", sender.getClass().getSimpleName());
        eventMetadata.put("messageSenderUserId", sender.getUser() != null ? sender.getUser().getId() : null);
        eventMetadata.put("messageSenderAccountId", sender.getAccount() != null ? sender.getAccount().getId() : null);
        eventMetadata.put("messageSenderAlias", sender.getAlias());
        eventMetadata.put("messageSenderHashtags", sender.getHashtags());
        eventMetadata.put("messageSenderVisibility", sender.getVisibility());
        eventMetadata.put("messageSenderVersion", sender.getVersion());

        // Connection metadata
        eventMetadata.put("messageConnectionId", connection != null ? connection.getId() : null);
        eventMetadata.put("messageConnectionAlias", connection != null ? connection.getAlias() : null);
        eventMetadata.put("messageConnectionHashtags", connection != null ? connection.getHashtags() : null);
        eventMetadata.put("messageConnectionVersion", connection != null ? connection.getVersion() : null);

        // Connection provider metadata
        ConnectionProvider cProvider = connection != null ?
                connectionProviderFactory.connectionProviderFromId(connection.getProviderId()) :
                null;

        eventMetadata.put("messageProviderId", cProvider != null ? cProvider.getId() : null);
        eventMetadata.put("messageProviderDisplayName", cProvider != null ? cProvider.getDisplayName() : null);
        eventMetadata.put("messageProviderType", cProvider != null ? cProvider.getType() : null);

        eventService.createEvent(EventId.CREATE, message, eventMetadata);

        // the the message and creation event, attempt to persist to outbound.
        try {
            outboundStorageService.sendSobaMessage(message);
        } catch (OutboundStorageException e) {
            logger.error("Unable to save processed message to outbound connections", e);
        }

        return message;
    }


    @SuppressWarnings("rawtypes")
    protected void saveMessage(SobaObject sender, SobaMessage message) {
        SobaObject.Visibility visibility = message.getVisibility();
        switch (visibility) {
            case PUBLIC:
                // give a copy to everyone
                sobaMessageDAO.saveToInboxes(userService.getAccounts(), message);
                // save in public archive repo
                sobaMessageDAO.save(message);
                break;

            default:
                // all other types are just in the one account inbox
                sobaMessageDAO.saveToInbox(sender.getAccount(), message);
                break;
        }
    }


    @Override
    public void updateMessage(Account account, SobaMessage sobaMessage) throws MessageNotFoundException {
        // verify it exists first
        SobaMessage message = sobaMessageDAO.getFromInbox(account, sobaMessage.getId());
        if (message == null) {
            throw new MessageNotFoundException(sobaMessage.getId().toString());
        }
        sobaMessageDAO.saveToInbox(account, sobaMessage);
    }


    @Override
    public void addCommentToMessage(Account account, ObjectId messageId, MessageComment comment, Set<String> hashtags)
            throws MessageNotFoundException {
        SobaMessage message = getMessage(account, messageId);
        message.addComment(comment);
        if (hashtags != null && !hashtags.isEmpty()) {
            message.addHashtags(hashtags);
        }
        updateMessage(account, message);
        emailService.sendCommentAddedEmail(account, message, comment);
    }

    @Override
    public void addHashtagToMessage(Account account, ObjectId messageId, String hashtag) throws MessageNotFoundException {
        SobaMessage message = getMessage(account, messageId);

        message.addHashtag(hashtag);
        updateMessage(account, message);
    }

    @Override
    public void removeHashtagFromMessage(Account account, ObjectId messageId, String hashtag) throws MessageNotFoundException {
        SobaMessage message = getMessage(account, messageId);
        message.removeHashtag(hashtag);
        updateMessage(account, message);
    }

    @Override
    public void copyArchivedMessagesToInbox(Account account) {
        // get all messages from the archive.
        List<SobaMessage> messages = sobaMessageDAO.getPublicArchivedMessages();
        logger.info("Copying " + messages.size() + " archived messages to account inbox " + account.getFuid());
        for (SobaMessage message : messages) {
            sobaMessageDAO.saveToInbox(account, message);
        }
    }

    @Override
    public void removeSampleMessages(Account account, ObjectId connectionId) {
        sobaMessageDAO.removeMessagesFromConnection(account, connectionId);
    }

    /**
     * Remove all messages and the collection for this account.
     *
     * @param account - the account to kill
     */
    @Override
    public void removeAllMessages(Account account) {
        sobaMessageDAO.removeInbox(account);
    }

    @Override
    public void nullifyMessage(User user, SobaMessage sobaMessage) {
        try {
            String nullify = MessageFormat.format(messageProperties.getProperty("message.removed.by"),
                    user.getAlias());
            sobaMessage.setDetails(null);
            sobaMessage.setTransformedMessage(nullify);
            updateMessage(user.getAccount(), sobaMessage);
        } catch (MessageNotFoundException e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    public void nullifyMessageComment(User user, SobaMessage sobaMessage, MessageComment messageComment) {
        try {
            String nullify = MessageFormat.format(messageProperties.getProperty("message.comment.removed.by"),
                    user.getAlias());
            for (MessageComment comment : sobaMessage.getComments()) {
                if (comment.equals(messageComment)) {
                    comment.setComment(nullify);
                    comment.setCreated(new Date().getTime());
                    updateMessage(user.getAccount(), sobaMessage);
                    break;
                }
            }

        } catch (MessageNotFoundException e) {
            logger.error(e.getMessage(), e);
        }


    }
}
TOP

Related Classes of com.streamreduce.core.service.MessageServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.