com.liferay.portlet.messageboards.service.impl.MBMessageLocalServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portlet.messageboards.service.impl.MBMessageLocalServiceImpl.java

Source

/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.portlet.messageboards.service.impl;

import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.search.IndexerRegistryUtil;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.ObjectValuePair;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
import com.liferay.portal.model.Company;
import com.liferay.portal.model.CompanyConstants;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.ModelHintsUtil;
import com.liferay.portal.model.ResourceConstants;
import com.liferay.portal.model.User;
import com.liferay.portal.security.auth.PrincipalException;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.ServiceContextUtil;
import com.liferay.portal.util.Portal;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portal.util.PortletKeys;
import com.liferay.portal.util.PrefsPropsUtil;
import com.liferay.portal.util.PropsValues;
import com.liferay.portal.util.SubscriptionSender;
import com.liferay.portlet.asset.model.AssetEntry;
import com.liferay.portlet.asset.model.AssetLinkConstants;
import com.liferay.portlet.blogs.model.BlogsEntry;
import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
import com.liferay.portlet.documentlibrary.DuplicateFileException;
import com.liferay.portlet.documentlibrary.NoSuchDirectoryException;
import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
import com.liferay.portlet.expando.model.ExpandoBridge;
import com.liferay.portlet.messageboards.MessageSubjectException;
import com.liferay.portlet.messageboards.NoSuchDiscussionException;
import com.liferay.portlet.messageboards.RequiredMessageException;
import com.liferay.portlet.messageboards.model.MBCategory;
import com.liferay.portlet.messageboards.model.MBCategoryConstants;
import com.liferay.portlet.messageboards.model.MBDiscussion;
import com.liferay.portlet.messageboards.model.MBMessage;
import com.liferay.portlet.messageboards.model.MBMessageConstants;
import com.liferay.portlet.messageboards.model.MBMessageDisplay;
import com.liferay.portlet.messageboards.model.MBThread;
import com.liferay.portlet.messageboards.model.MBThreadConstants;
import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
import com.liferay.portlet.messageboards.model.impl.MBMessageDisplayImpl;
import com.liferay.portlet.messageboards.service.base.MBMessageLocalServiceBaseImpl;
import com.liferay.portlet.messageboards.social.MBActivityKeys;
import com.liferay.portlet.messageboards.util.MBSubscriptionSender;
import com.liferay.portlet.messageboards.util.MBUtil;
import com.liferay.portlet.messageboards.util.MailingListThreadLocal;
import com.liferay.portlet.messageboards.util.comparator.MessageCreateDateComparator;
import com.liferay.portlet.messageboards.util.comparator.MessageThreadComparator;
import com.liferay.portlet.messageboards.util.comparator.ThreadLastPostDateComparator;
import com.liferay.portlet.social.model.SocialActivity;
import com.liferay.portlet.social.model.SocialActivityConstants;
import com.liferay.util.SerializableUtil;

import java.io.InputStream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.portlet.PortletPreferences;

import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.StartTag;

/**
 * @author Brian Wing Shun Chan
 * @author Raymond Aug
 * @author Mika Koivisto
 * @author Jorge Ferrer
 * @author Juan Fernndez
 * @author Shuyang Zhou
 */
public class MBMessageLocalServiceImpl extends MBMessageLocalServiceBaseImpl {

    public MBMessage addDiscussionMessage(long userId, String userName, long groupId, String className,
            long classPK, int workflowAction) throws PortalException, SystemException {

        long threadId = 0;
        long parentMessageId = 0;
        String subject = String.valueOf(classPK);
        String body = subject;

        ServiceContext serviceContext = new ServiceContext();

        serviceContext.setWorkflowAction(workflowAction);

        boolean workflowEnabled = WorkflowThreadLocal.isEnabled();

        WorkflowThreadLocal.setEnabled(false);

        try {
            return addDiscussionMessage(userId, userName, groupId, className, classPK, threadId, parentMessageId,
                    subject, body, serviceContext);
        } finally {
            WorkflowThreadLocal.setEnabled(workflowEnabled);
        }
    }

    public MBMessage addDiscussionMessage(long userId, String userName, long groupId, String className,
            long classPK, long threadId, long parentMessageId, String subject, String body,
            ServiceContext serviceContext) throws PortalException, SystemException {

        // Message

        long categoryId = MBCategoryConstants.DISCUSSION_CATEGORY_ID;

        if (Validator.isNull(subject)) {
            subject = body.substring(0, Math.min(body.length(), 50)) + "...";
        }

        List<ObjectValuePair<String, InputStream>> inputStreamOVPs = Collections.emptyList();
        boolean anonymous = false;
        double priority = 0.0;
        boolean allowPingbacks = false;

        serviceContext.setAddGroupPermissions(true);
        serviceContext.setAddGuestPermissions(true);
        serviceContext.setAttribute("className", className);
        serviceContext.setAttribute("classPK", String.valueOf(classPK));

        MBMessage message = addMessage(userId, userName, groupId, categoryId, threadId, parentMessageId, subject,
                body, MBMessageConstants.DEFAULT_FORMAT, inputStreamOVPs, anonymous, priority, allowPingbacks,
                serviceContext);

        // Discussion

        if (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
            long classNameId = PortalUtil.getClassNameId(className);

            MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(classNameId, classPK);

            if (discussion == null) {
                discussion = mbDiscussionLocalService.addDiscussion(classNameId, classPK, message.getThreadId());
            }
        }

        return message;
    }

    public MBMessage addMessage(long userId, String userName, long groupId, long categoryId, long threadId,
            long parentMessageId, String subject, String body, String format,
            List<ObjectValuePair<String, InputStream>> inputStreamOVPs, boolean anonymous, double priority,
            boolean allowPingbacks, ServiceContext serviceContext) throws PortalException, SystemException {

        // Message

        User user = userPersistence.findByPrimaryKey(userId);
        userName = user.isDefaultUser() ? userName : user.getFullName();
        subject = ModelHintsUtil.trimString(MBMessage.class.getName(), "subject", subject);

        PortletPreferences preferences = ServiceContextUtil.getPortletPreferences(serviceContext);

        if (preferences != null) {
            if (!MBUtil.isAllowAnonymousPosting(preferences)) {
                if (anonymous || user.isDefaultUser()) {
                    throw new PrincipalException();
                }
            }
        }

        if (user.isDefaultUser()) {
            anonymous = true;
        }

        Date now = new Date();

        long messageId = counterLocalService.increment();

        body = SanitizerUtil.sanitize(user.getCompanyId(), groupId, userId, MBMessage.class.getName(), messageId,
                "text/" + format, body);

        validate(subject, body);

        subject = getSubject(subject, body);
        body = getBody(subject, body);

        MBMessage message = mbMessagePersistence.create(messageId);

        message.setUuid(serviceContext.getUuid());
        message.setGroupId(groupId);
        message.setCompanyId(user.getCompanyId());
        message.setUserId(user.getUserId());
        message.setUserName(userName);
        message.setCreateDate(serviceContext.getCreateDate(now));
        message.setModifiedDate(serviceContext.getModifiedDate(now));

        if (threadId > 0) {
            message.setThreadId(threadId);
        }

        if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
            message.setPriority(priority);
        }

        message.setAllowPingbacks(allowPingbacks);
        message.setStatus(WorkflowConstants.STATUS_DRAFT);
        message.setStatusByUserId(user.getUserId());
        message.setStatusByUserName(userName);
        message.setStatusDate(serviceContext.getModifiedDate(now));

        // Thread

        if (parentMessageId != MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
            MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(parentMessageId);

            if (parentMessage == null) {
                parentMessageId = MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID;
            }
        }

        MBThread thread = null;

        if (threadId > 0) {
            thread = mbThreadPersistence.fetchByPrimaryKey(threadId);
        }

        if ((thread == null) || (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID)) {

            thread = mbThreadLocalService.addThread(categoryId, message);
        }

        if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) && (thread.getPriority() != priority)) {

            thread.setPriority(priority);

            mbThreadPersistence.update(thread, false);

            updatePriorities(thread.getThreadId(), priority);
        }

        // Message

        message.setCategoryId(categoryId);
        message.setThreadId(thread.getThreadId());
        message.setRootMessageId(thread.getRootMessageId());
        message.setParentMessageId(parentMessageId);
        message.setSubject(subject);
        message.setBody(body);
        message.setFormat(format);
        message.setAttachments(!inputStreamOVPs.isEmpty());
        message.setAnonymous(anonymous);

        if (message.isDiscussion()) {
            long classNameId = PortalUtil.getClassNameId((String) serviceContext.getAttribute("className"));
            long classPK = GetterUtil.getLong((String) serviceContext.getAttribute("classPK"));

            message.setClassNameId(classNameId);
            message.setClassPK(classPK);
        }

        mbMessagePersistence.update(message, false);

        // Attachments

        if (!inputStreamOVPs.isEmpty()) {
            long companyId = message.getCompanyId();
            long repositoryId = CompanyConstants.SYSTEM;
            String dirName = message.getAttachmentsDir();

            try {
                DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
            } catch (NoSuchDirectoryException nsde) {
                if (_log.isDebugEnabled()) {
                    _log.debug(nsde.getMessage());
                }
            }

            DLStoreUtil.addDirectory(companyId, repositoryId, dirName);

            for (int i = 0; i < inputStreamOVPs.size(); i++) {
                ObjectValuePair<String, InputStream> inputStreamOVP = inputStreamOVPs.get(i);

                String fileName = inputStreamOVP.getKey();
                InputStream inputStream = inputStreamOVP.getValue();

                try {
                    DLStoreUtil.addFile(companyId, repositoryId, dirName + "/" + fileName, inputStream);
                } catch (DuplicateFileException dfe) {
                    if (_log.isDebugEnabled()) {
                        _log.debug(dfe.getMessage());
                    }
                }
            }
        }

        // Resources

        if (!message.isDiscussion()) {
            if (user.isDefaultUser()) {
                addMessageResources(message, true, true);
            } else if (serviceContext.isAddGroupPermissions() || serviceContext.isAddGuestPermissions()) {

                addMessageResources(message, serviceContext.isAddGroupPermissions(),
                        serviceContext.isAddGuestPermissions());
            } else {
                addMessageResources(message, serviceContext.getGroupPermissions(),
                        serviceContext.getGuestPermissions());
            }
        }

        // Asset

        updateAsset(userId, message, serviceContext.getAssetCategoryIds(), serviceContext.getAssetTagNames(),
                serviceContext.getAssetLinkEntryIds(), serviceContext.isAssetEntryVisible());

        // Expando

        ExpandoBridge expandoBridge = message.getExpandoBridge();

        expandoBridge.setAttributes(serviceContext);

        // Workflow

        WorkflowHandlerRegistryUtil.startWorkflowInstance(user.getCompanyId(), groupId, userId,
                message.getWorkflowClassName(), message.getMessageId(), message, serviceContext);

        // Testing roll back

        /*if (true) {
           throw new SystemException("Testing roll back");
        }*/

        return message;
    }

    public MBMessage addMessage(long userId, String userName, long groupId, long categoryId, String subject,
            String body, String format, List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
            boolean anonymous, double priority, boolean allowPingbacks, ServiceContext serviceContext)
            throws PortalException, SystemException {

        long threadId = 0;
        long parentMessageId = 0;

        return addMessage(userId, userName, groupId, categoryId, threadId, parentMessageId, subject, body, format,
                inputStreamOVPs, anonymous, priority, allowPingbacks, serviceContext);
    }

    public void addMessageResources(long messageId, boolean addGroupPermissions, boolean addGuestPermissions)
            throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        addMessageResources(message, addGroupPermissions, addGuestPermissions);
    }

    public void addMessageResources(long messageId, String[] groupPermissions, String[] guestPermissions)
            throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        addMessageResources(message, groupPermissions, guestPermissions);
    }

    public void addMessageResources(MBMessage message, boolean addGroupPermissions, boolean addGuestPermissions)
            throws PortalException, SystemException {

        resourceLocalService.addResources(message.getCompanyId(), message.getGroupId(), message.getUserId(),
                MBMessage.class.getName(), message.getMessageId(), false, addGroupPermissions, addGuestPermissions);
    }

    public void addMessageResources(MBMessage message, String[] groupPermissions, String[] guestPermissions)
            throws PortalException, SystemException {

        resourceLocalService.addModelResources(message.getCompanyId(), message.getGroupId(), message.getUserId(),
                MBMessage.class.getName(), message.getMessageId(), groupPermissions, guestPermissions);
    }

    public void deleteDiscussionMessage(long messageId) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        deleteDiscussionSocialActivities(BlogsEntry.class.getName(), message);

        deleteMessage(message);
    }

    public void deleteDiscussionMessages(String className, long classPK) throws PortalException, SystemException {

        try {
            long classNameId = PortalUtil.getClassNameId(className);

            MBDiscussion discussion = mbDiscussionPersistence.findByC_C(classNameId, classPK);

            List<MBMessage> messages = mbMessagePersistence.findByT_P(discussion.getThreadId(),
                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, 0, 1);

            if (!messages.isEmpty()) {
                MBMessage message = messages.get(0);

                deleteDiscussionSocialActivities(BlogsEntry.class.getName(), message);

                mbThreadLocalService.deleteThread(message.getThreadId());
            }

            mbDiscussionPersistence.remove(discussion);
        } catch (NoSuchDiscussionException nsde) {
            if (_log.isDebugEnabled()) {
                _log.debug(nsde.getMessage());
            }
        }
    }

    public void deleteMessage(long messageId) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        deleteMessage(message);
    }

    public void deleteMessage(MBMessage message) throws PortalException, SystemException {

        // Indexer

        Indexer indexer = IndexerRegistryUtil.getIndexer(MBMessage.class);

        indexer.delete(message);

        // Attachments

        if (message.isAttachments()) {
            long companyId = message.getCompanyId();
            long repositoryId = CompanyConstants.SYSTEM;
            String dirName = message.getAttachmentsDir();

            try {
                DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
            } catch (NoSuchDirectoryException nsde) {
                if (_log.isDebugEnabled()) {
                    _log.debug(nsde.getMessage());
                }
            }
        }

        // Thread

        int count = mbMessagePersistence.countByThreadId(message.getThreadId());

        if (count == 1) {

            // Attachments

            long companyId = message.getCompanyId();
            long repositoryId = CompanyConstants.SYSTEM;
            String dirName = message.getThreadAttachmentsDir();

            try {
                DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
            } catch (NoSuchDirectoryException nsde) {
                if (_log.isDebugEnabled()) {
                    _log.debug(nsde.getMessage());
                }
            }

            // Subscriptions

            subscriptionLocalService.deleteSubscriptions(message.getCompanyId(), MBThread.class.getName(),
                    message.getThreadId());

            // Thread

            mbThreadPersistence.remove(message.getThreadId());

            // Category

            if ((message.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
                    && (message.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {

                MBCategory category = mbCategoryPersistence.findByPrimaryKey(message.getCategoryId());

                category.setThreadCount(category.getThreadCount() - 1);
                category.setMessageCount(category.getMessageCount() - 1);

                mbCategoryPersistence.update(category, false);
            }
        } else {
            MBThread thread = mbThreadPersistence.findByPrimaryKey(message.getThreadId());

            // Message is a root message

            if (thread.getRootMessageId() == message.getMessageId()) {
                List<MBMessage> childrenMessages = mbMessagePersistence.findByT_P(message.getThreadId(),
                        message.getMessageId());

                if (childrenMessages.size() > 1) {
                    throw new RequiredMessageException(String.valueOf(message.getMessageId()));
                } else if (childrenMessages.size() == 1) {
                    MBMessage childMessage = childrenMessages.get(0);

                    childMessage.setRootMessageId(childMessage.getMessageId());
                    childMessage.setParentMessageId(MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);

                    mbMessagePersistence.update(childMessage, false);

                    thread.setRootMessageId(childMessage.getMessageId());
                    thread.setRootMessageUserId(childMessage.getUserId());

                    mbThreadPersistence.update(thread, false);
                }
            }

            // Message is a child message

            else {
                List<MBMessage> childrenMessages = mbMessagePersistence.findByT_P(message.getThreadId(),
                        message.getMessageId());

                // Message has children messages

                if (!childrenMessages.isEmpty()) {
                    Iterator<MBMessage> itr = childrenMessages.iterator();

                    while (itr.hasNext()) {
                        MBMessage childMessage = itr.next();

                        childMessage.setParentMessageId(message.getParentMessageId());

                        mbMessagePersistence.update(childMessage, false);
                    }
                } else {
                    MessageCreateDateComparator comparator = new MessageCreateDateComparator(true);

                    MBMessage lastMessage = mbMessagePersistence.findByT_S_Last(thread.getThreadId(),
                            WorkflowConstants.STATUS_APPROVED, comparator);

                    if (message.getMessageId() == lastMessage.getMessageId()) {
                        MBMessage parentMessage = mbMessagePersistence
                                .findByPrimaryKey(message.getParentMessageId());

                        thread.setLastPostByUserId(parentMessage.getUserId());
                        thread.setLastPostDate(parentMessage.getModifiedDate());
                    }
                }
            }

            // Thread

            if (message.isApproved()) {
                int messageCount = mbMessagePersistence.countByT_S(message.getThreadId(),
                        WorkflowConstants.STATUS_APPROVED);

                thread.setMessageCount(messageCount - 1);
            }

            mbThreadPersistence.update(thread, false);

            // Category

            if ((message.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
                    && (message.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)
                    && !message.isDraft()) {

                MBCategory category = mbCategoryPersistence.findByPrimaryKey(message.getCategoryId());

                category.setMessageCount(category.getMessageCount() - 1);

                mbCategoryPersistence.update(category, false);
            }
        }

        // Asset

        assetEntryLocalService.deleteEntry(MBMessage.class.getName(), message.getMessageId());

        // Expando

        expandoValueLocalService.deleteValues(MBMessage.class.getName(), message.getMessageId());

        // Ratings

        ratingsStatsLocalService.deleteStats(MBMessage.class.getName(), message.getMessageId());

        // Resources

        if (!message.isDiscussion()) {
            resourceLocalService.deleteResource(message.getCompanyId(), MBMessage.class.getName(),
                    ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
        }

        // Message

        mbMessagePersistence.remove(message);

        // Statistics

        if (!message.isDiscussion()) {
            mbStatsUserLocalService.updateStatsUser(message.getGroupId(), message.getUserId());
        }

        // Workflow

        workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(message.getCompanyId(), message.getGroupId(),
                message.getWorkflowClassName(), message.getMessageId());
    }

    public List<MBMessage> getCategoryMessages(long groupId, long categoryId, int status, int start, int end)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByG_C(groupId, categoryId, start, end);
        } else {
            return mbMessagePersistence.findByG_C_S(groupId, categoryId, status, start, end);
        }
    }

    public List<MBMessage> getCategoryMessages(long groupId, long categoryId, int status, int start, int end,
            OrderByComparator obc) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByG_C(groupId, categoryId, start, end, obc);
        } else {
            return mbMessagePersistence.findByG_C_S(groupId, categoryId, status, start, end, obc);
        }
    }

    public int getCategoryMessagesCount(long groupId, long categoryId, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByG_C(groupId, categoryId);
        } else {
            return mbMessagePersistence.countByG_C_S(groupId, categoryId, status);
        }
    }

    public List<MBMessage> getCompanyMessages(long companyId, int status, int start, int end)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByCompanyId(companyId, start, end);
        } else {
            return mbMessagePersistence.findByC_S(companyId, status, start, end);
        }
    }

    public List<MBMessage> getCompanyMessages(long companyId, int status, int start, int end, OrderByComparator obc)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByCompanyId(companyId, start, end, obc);
        } else {
            return mbMessagePersistence.findByC_S(companyId, status, start, end, obc);
        }
    }

    public int getCompanyMessagesCount(long companyId, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByCompanyId(companyId);
        } else {
            return mbMessagePersistence.countByC_S(companyId, status);
        }
    }

    public MBMessageDisplay getDiscussionMessageDisplay(long userId, long groupId, String className, long classPK,
            int status) throws PortalException, SystemException {

        return getDiscussionMessageDisplay(userId, groupId, className, classPK, status,
                MBThreadConstants.THREAD_VIEW_COMBINATION);
    }

    public MBMessageDisplay getDiscussionMessageDisplay(long userId, long groupId, String className, long classPK,
            int status, String threadView) throws PortalException, SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        MBMessage message = null;

        MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(classNameId, classPK);

        if (discussion != null) {
            List<MBMessage> messages = mbMessagePersistence.findByT_P(discussion.getThreadId(),
                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);

            message = messages.get(0);
        } else {
            boolean workflowEnabled = WorkflowThreadLocal.isEnabled();

            WorkflowThreadLocal.setEnabled(false);

            try {
                String subject = String.valueOf(classPK);
                //String body = subject;

                message = addDiscussionMessage(userId, null, groupId, className, classPK, 0,
                        MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, subject, subject, new ServiceContext());
            } catch (SystemException se) {
                if (_log.isWarnEnabled()) {
                    _log.warn("Add failed, fetch {threadId=0, parentMessageId="
                            + MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID + "}");
                }

                List<MBMessage> messages = mbMessagePersistence.findByT_P(0,
                        MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);

                if (messages.isEmpty()) {
                    throw se;
                }

                message = messages.get(0);
            } finally {
                WorkflowThreadLocal.setEnabled(workflowEnabled);
            }
        }

        return getMessageDisplay(userId, message, status, threadView, false);
    }

    public int getDiscussionMessagesCount(long classNameId, long classPK, int status) throws SystemException {

        MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(classNameId, classPK);

        if (discussion == null) {
            return 0;
        }

        int count = 0;

        if (status == WorkflowConstants.STATUS_ANY) {
            count = mbMessagePersistence.countByThreadId(discussion.getThreadId());
        } else {
            count = mbMessagePersistence.countByT_S(discussion.getThreadId(), status);
        }

        if (count >= 1) {
            return count - 1;
        } else {
            return 0;
        }
    }

    public int getDiscussionMessagesCount(String className, long classPK, int status) throws SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        return getDiscussionMessagesCount(classNameId, classPK, status);
    }

    public List<MBDiscussion> getDiscussions(String className) throws SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        return mbDiscussionPersistence.findByClassNameId(classNameId);
    }

    public List<MBMessage> getGroupMessages(long groupId, int status, int start, int end) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByGroupId(groupId, start, end);
        } else {
            return mbMessagePersistence.findByG_S(groupId, status, start, end);
        }
    }

    public List<MBMessage> getGroupMessages(long groupId, int status, int start, int end, OrderByComparator obc)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByGroupId(groupId, start, end, obc);
        } else {
            return mbMessagePersistence.findByG_S(groupId, status, start, end, obc);
        }
    }

    public List<MBMessage> getGroupMessages(long groupId, long userId, int status, int start, int end)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByG_U(groupId, userId, start, end);
        } else {
            return mbMessagePersistence.findByG_U_S(groupId, userId, status, start, end);
        }
    }

    public List<MBMessage> getGroupMessages(long groupId, long userId, int status, int start, int end,
            OrderByComparator obc) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByG_U(groupId, userId, start, end, obc);
        } else {
            return mbMessagePersistence.findByG_U_S(groupId, userId, status, start, end, obc);
        }
    }

    public int getGroupMessagesCount(long groupId, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByGroupId(groupId);
        } else {
            return mbMessagePersistence.countByG_S(groupId, status);
        }
    }

    public int getGroupMessagesCount(long groupId, long userId, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByG_U(groupId, userId);
        } else {
            return mbMessagePersistence.countByG_U_S(groupId, userId, status);
        }
    }

    public MBMessage getMessage(long messageId) throws PortalException, SystemException {

        return mbMessagePersistence.findByPrimaryKey(messageId);
    }

    public MBMessageDisplay getMessageDisplay(long userId, long messageId, int status, String threadView,
            boolean includePrevAndNext) throws PortalException, SystemException {

        MBMessage message = getMessage(messageId);

        return getMessageDisplay(userId, message, status, threadView, includePrevAndNext);
    }

    public MBMessageDisplay getMessageDisplay(long userId, MBMessage message, int status, String threadView,
            boolean includePrevAndNext) throws PortalException, SystemException {

        MBCategory category = null;

        if ((message.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
                && (message.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {

            category = mbCategoryPersistence.findByPrimaryKey(message.getCategoryId());
        } else {
            category = new MBCategoryImpl();

            category.setCategoryId(message.getCategoryId());
            category.setDisplayStyle(MBCategoryConstants.DEFAULT_DISPLAY_STYLE);
        }

        MBMessage parentMessage = null;

        if (message.isReply()) {
            parentMessage = mbMessagePersistence.findByPrimaryKey(message.getParentMessageId());
        }

        MBThread thread = mbThreadPersistence.findByPrimaryKey(message.getThreadId());

        if (message.isApproved() && !message.isDiscussion()) {
            mbThreadLocalService.incrementViewCounter(thread.getThreadId(), 1);

            if (thread.getRootMessageUserId() != userId) {
                MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(thread.getRootMessageId());

                socialActivityLocalService.addActivity(userId, rootMessage.getGroupId(), MBMessage.class.getName(),
                        rootMessage.getMessageId(), SocialActivityConstants.TYPE_VIEW, StringPool.BLANK, 0);
            }
        }

        MBThread previousThread = null;
        MBThread nextThread = null;

        if (message.isApproved() && includePrevAndNext) {
            ThreadLastPostDateComparator comparator = new ThreadLastPostDateComparator(false);

            MBThread[] prevAndNextThreads = mbThreadPersistence.findByG_C_PrevAndNext(message.getThreadId(),
                    message.getGroupId(), message.getCategoryId(), comparator);

            previousThread = prevAndNextThreads[0];
            nextThread = prevAndNextThreads[2];
        }

        return new MBMessageDisplayImpl(message, parentMessage, category, thread, previousThread, nextThread,
                status, threadView, this);
    }

    public List<MBMessage> getMessages(String className, long classPK, int status) throws SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByC_C(classNameId, classPK);
        } else {
            return mbMessagePersistence.findByC_C_S(classNameId, classPK, status);
        }
    }

    public List<MBMessage> getNoAssetMessages() throws SystemException {
        return mbMessageFinder.findByNoAssets();
    }

    public int getPositionInThread(long messageId) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        return mbMessageFinder.countByC_T(message.getCreateDate(), message.getThreadId());
    }

    public List<MBMessage> getThreadMessages(long threadId, int status) throws SystemException {

        return getThreadMessages(threadId, status, new MessageThreadComparator());
    }

    public List<MBMessage> getThreadMessages(long threadId, int status, Comparator<MBMessage> comparator)
            throws SystemException {

        List<MBMessage> messages = null;

        if (status == WorkflowConstants.STATUS_ANY) {
            messages = mbMessagePersistence.findByThreadId(threadId);
        } else {
            messages = mbMessagePersistence.findByT_S(threadId, status);
        }

        return ListUtil.sort(messages, comparator);
    }

    public List<MBMessage> getThreadMessages(long threadId, int status, int start, int end) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByThreadId(threadId, start, end);
        } else {
            return mbMessagePersistence.findByT_S(threadId, status, start, end);
        }
    }

    public int getThreadMessagesCount(long threadId, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByThreadId(threadId);
        } else {
            return mbMessagePersistence.countByT_S(threadId, status);
        }
    }

    public List<MBMessage> getThreadRepliesMessages(long threadId, int status, int start, int end)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByThreadReplies(threadId, start, end);
        } else {
            return mbMessagePersistence.findByTR_S(threadId, status, start, end);
        }
    }

    public List<MBMessage> getUserDiscussionMessages(long userId, long classNameId, long classPK, int status,
            int start, int end, OrderByComparator obc) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByU_C_C(userId, classNameId, classPK, start, end, obc);
        } else {
            return mbMessagePersistence.findByU_C_C_S(userId, classNameId, classPK, status, start, end, obc);
        }
    }

    public List<MBMessage> getUserDiscussionMessages(long userId, long[] classNameIds, int status, int start,
            int end, OrderByComparator obc) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.findByU_C(userId, classNameIds, start, end, obc);
        } else {
            return mbMessagePersistence.findByU_C_S(userId, classNameIds, status, start, end, obc);
        }
    }

    public List<MBMessage> getUserDiscussionMessages(long userId, String className, long classPK, int status,
            int start, int end, OrderByComparator obc) throws SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        return getUserDiscussionMessages(userId, classNameId, classPK, status, start, end, obc);
    }

    public int getUserDiscussionMessagesCount(long userId, long classNameId, long classPK, int status)
            throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByU_C_C(userId, classNameId, classPK);
        } else {
            return mbMessagePersistence.countByU_C_C_S(userId, classNameId, classPK, status);
        }
    }

    public int getUserDiscussionMessagesCount(long userId, long[] classNameIds, int status) throws SystemException {

        if (status == WorkflowConstants.STATUS_ANY) {
            return mbMessagePersistence.countByU_C(userId, classNameIds);
        } else {
            return mbMessagePersistence.countByU_C_S(userId, classNameIds, status);
        }
    }

    public int getUserDiscussionMessagesCount(long userId, String className, long classPK, int status)
            throws SystemException {

        long classNameId = PortalUtil.getClassNameId(className);

        return getUserDiscussionMessagesCount(userId, classNameId, classPK, status);
    }

    public void subscribeMessage(long userId, long messageId) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        subscriptionLocalService.addSubscription(userId, message.getGroupId(), MBThread.class.getName(),
                message.getThreadId());
    }

    public void unsubscribeMessage(long userId, long messageId) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        subscriptionLocalService.deleteSubscription(userId, MBThread.class.getName(), message.getThreadId());
    }

    public void updateAnswer(long messageId, boolean answer, boolean cascade)
            throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        updateAnswer(message, answer, cascade);
    }

    public void updateAnswer(MBMessage message, boolean answer, boolean cascade)
            throws PortalException, SystemException {

        if (message.isAnswer() != answer) {
            message.setAnswer(answer);

            mbMessagePersistence.update(message, false);
        }

        if (cascade) {
            List<MBMessage> messages = mbMessagePersistence.findByT_P(message.getThreadId(),
                    message.getMessageId());

            for (MBMessage curMessage : messages) {
                updateAnswer(curMessage, answer, cascade);
            }
        }
    }

    public void updateAsset(long userId, MBMessage message, long[] assetCategoryIds, String[] assetTagNames,
            long[] assetLinkEntryIds) throws PortalException, SystemException {

        updateAsset(userId, message, assetCategoryIds, assetTagNames, assetLinkEntryIds, true);
    }

    public MBMessage updateDiscussionMessage(long userId, long messageId, String className, long classPK,
            String subject, String body, ServiceContext serviceContext) throws PortalException, SystemException {

        if (Validator.isNull(subject)) {
            subject = body.substring(0, Math.min(body.length(), 50)) + "...";
        }

        List<ObjectValuePair<String, InputStream>> inputStreamOVPs = Collections.emptyList();
        List<String> existingFiles = new ArrayList<String>();
        double priority = 0.0;
        boolean allowPingbacks = false;

        serviceContext.setAttribute("className", className);
        serviceContext.setAttribute("classPK", String.valueOf(classPK));

        return updateMessage(userId, messageId, subject, body, inputStreamOVPs, existingFiles, priority,
                allowPingbacks, serviceContext);
    }

    public MBMessage updateMessage(long userId, long messageId, String subject, String body,
            List<ObjectValuePair<String, InputStream>> inputStreamOVPs, List<String> existingFiles, double priority,
            boolean allowPingbacks, ServiceContext serviceContext) throws PortalException, SystemException {

        // Message

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        subject = ModelHintsUtil.trimString(MBMessage.class.getName(), "subject", subject);
        body = SanitizerUtil.sanitize(message.getCompanyId(), message.getGroupId(), userId,
                MBMessage.class.getName(), messageId, "text/" + message.getFormat(), body);
        Date now = new Date();

        validate(subject, body);

        subject = getSubject(subject, body);
        body = getBody(subject, body);

        message.setModifiedDate(serviceContext.getModifiedDate(now));
        message.setSubject(subject);
        message.setBody(body);
        message.setAttachments(!inputStreamOVPs.isEmpty() || !existingFiles.isEmpty());
        message.setAllowPingbacks(allowPingbacks);

        if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
            message.setPriority(priority);
        }

        if (!message.isPending() && (serviceContext.getWorkflowAction() == WorkflowConstants.ACTION_SAVE_DRAFT)) {

            message.setStatus(WorkflowConstants.STATUS_DRAFT);
        }

        // Attachments

        long companyId = message.getCompanyId();
        long repositoryId = CompanyConstants.SYSTEM;
        String dirName = message.getAttachmentsDir();

        if (!inputStreamOVPs.isEmpty() || !existingFiles.isEmpty()) {
            try {
                DLStoreUtil.addDirectory(companyId, repositoryId, dirName);
            } catch (DuplicateDirectoryException dde) {
            }

            String[] fileNames = DLStoreUtil.getFileNames(companyId, repositoryId, dirName);

            for (String fileName : fileNames) {
                if (!existingFiles.contains(fileName)) {
                    DLStoreUtil.deleteFile(companyId, repositoryId, fileName);
                }
            }

            for (int i = 0; i < inputStreamOVPs.size(); i++) {
                ObjectValuePair<String, InputStream> inputStreamOVP = inputStreamOVPs.get(i);

                String fileName = inputStreamOVP.getKey();
                InputStream inputStream = inputStreamOVP.getValue();

                try {
                    DLStoreUtil.addFile(companyId, repositoryId, dirName + "/" + fileName, inputStream);
                } catch (DuplicateFileException dfe) {
                }
            }
        } else {
            try {
                DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
            } catch (NoSuchDirectoryException nsde) {
            }
        }

        mbMessagePersistence.update(message, false);

        // Thread

        MBThread thread = mbThreadPersistence.findByPrimaryKey(message.getThreadId());

        if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) && (thread.getPriority() != priority)) {

            thread.setPriority(priority);

            mbThreadPersistence.update(thread, false);

            updatePriorities(thread.getThreadId(), priority);
        }

        // Asset

        updateAsset(userId, message, serviceContext.getAssetCategoryIds(), serviceContext.getAssetTagNames(),
                serviceContext.getAssetLinkEntryIds());

        // Expando

        ExpandoBridge expandoBridge = message.getExpandoBridge();

        expandoBridge.setAttributes(serviceContext);

        // Workflow

        serviceContext.setAttribute("update", Boolean.TRUE.toString());

        WorkflowHandlerRegistryUtil.startWorkflowInstance(companyId, message.getGroupId(), userId,
                message.getWorkflowClassName(), message.getMessageId(), message, serviceContext);

        return message;
    }

    public MBMessage updateMessage(long messageId, String body) throws PortalException, SystemException {

        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

        message.setBody(body);

        mbMessagePersistence.update(message, false);

        return message;
    }

    public MBMessage updateStatus(long userId, long messageId, int status, ServiceContext serviceContext)
            throws PortalException, SystemException {

        // Message

        MBMessage message = getMessage(messageId);

        int oldStatus = message.getStatus();

        User user = userPersistence.findByPrimaryKey(userId);
        Date now = new Date();

        message.setStatus(status);
        message.setStatusByUserId(userId);
        message.setStatusByUserName(user.getFullName());
        message.setStatusDate(serviceContext.getModifiedDate(now));

        mbMessagePersistence.update(message, false);

        // Thread

        MBThread thread = mbThreadPersistence.findByPrimaryKey(message.getThreadId());

        MBCategory category = null;

        if ((thread.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
                && (thread.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {

            category = mbCategoryPersistence.findByPrimaryKey(thread.getCategoryId());
        }

        if ((thread.getRootMessageId() == message.getMessageId()) && (oldStatus != status)) {

            thread.setStatus(status);
            thread.setStatusByUserId(userId);
            thread.setStatusByUserName(user.getFullName());
            thread.setStatusDate(serviceContext.getModifiedDate(now));
        }

        Indexer indexer = IndexerRegistryUtil.getIndexer(MBMessage.class);

        if (status == WorkflowConstants.STATUS_APPROVED) {
            if (oldStatus != WorkflowConstants.STATUS_APPROVED) {

                // Thread

                if ((category != null) && (thread.getRootMessageId() == message.getMessageId())) {

                    category.setThreadCount(category.getThreadCount() + 1);

                    mbCategoryPersistence.update(category, false);
                }

                thread.setMessageCount(thread.getMessageCount() + 1);

                if (message.isAnonymous()) {
                    thread.setLastPostByUserId(0);
                } else {
                    thread.setLastPostByUserId(message.getUserId());
                }

                thread.setLastPostDate(serviceContext.getModifiedDate(now));

                // Category

                if (category != null) {
                    category.setMessageCount(category.getMessageCount() + 1);
                    category.setLastPostDate(serviceContext.getModifiedDate(now));

                    mbCategoryPersistence.update(category, false);

                }

                // Asset

                if (serviceContext.isAssetEntryVisible()
                        && ((message.getClassNameId() == 0) || (message.getParentMessageId() != 0))) {

                    assetEntryLocalService.updateVisible(message.getWorkflowClassName(), message.getMessageId(),
                            true);
                }

                if (!message.isDiscussion()) {

                    // Social

                    if (!message.isAnonymous() && !user.isDefaultUser()) {
                        long receiverUserId = 0;

                        MBMessage parentMessage = mbMessagePersistence
                                .fetchByPrimaryKey(message.getParentMessageId());

                        if (parentMessage != null) {
                            receiverUserId = parentMessage.getUserId();
                        }

                        socialActivityLocalService.addActivity(userId, message.getGroupId(),
                                MBMessage.class.getName(), message.getMessageId(), MBActivityKeys.ADD_MESSAGE,
                                StringPool.BLANK, receiverUserId);

                        if ((parentMessage != null) && (receiverUserId != userId)) {

                            socialActivityLocalService.addActivity(userId, parentMessage.getGroupId(),
                                    MBMessage.class.getName(), parentMessage.getMessageId(),
                                    MBActivityKeys.REPLY_MESSAGE, StringPool.BLANK, 0);
                        }
                    }
                } else {

                    // Social

                    String className = (String) serviceContext.getAttribute("className");
                    long classPK = GetterUtil.getLong((String) serviceContext.getAttribute("classPK"));
                    long parentMessageId = message.getParentMessageId();

                    if (parentMessageId != MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {

                        AssetEntry assetEntry = assetEntryLocalService.fetchEntry(className, classPK);

                        if (assetEntry != null) {
                            JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();

                            extraDataJSONObject.put("messageId", message.getMessageId());

                            socialActivityLocalService.addActivity(userId, assetEntry.getGroupId(), className,
                                    classPK, SocialActivityConstants.TYPE_ADD_COMMENT,
                                    extraDataJSONObject.toString(), assetEntry.getUserId());
                        }
                    }
                }

                // Subscriptions

                notifySubscribers(message, serviceContext);
            }

            // Indexer

            if (!message.isDiscussion()) {
                indexer.reindex(message);
            }

            // Ping

            pingPingback(message, serviceContext);
        } else if ((oldStatus == WorkflowConstants.STATUS_APPROVED)
                && (status != WorkflowConstants.STATUS_APPROVED)) {

            // Thread

            if ((category != null) && (thread.getRootMessageId() == message.getMessageId())) {

                category.setThreadCount(category.getThreadCount() - 1);

                mbCategoryPersistence.update(category, false);
            }

            thread.setMessageCount(thread.getMessageCount() - 1);

            // Category

            if (category != null) {
                category.setMessageCount(category.getMessageCount() - 1);

                mbCategoryPersistence.update(category, false);
            }

            // Asset

            assetEntryLocalService.updateVisible(message.getWorkflowClassName(), message.getMessageId(), false);

            if (!message.isDiscussion()) {

                // Indexer

                indexer.delete(message);
            }
        }

        if (status != oldStatus) {
            mbThreadPersistence.update(thread, false);
        }

        // Statistics

        if (!message.isDiscussion()) {
            mbStatsUserLocalService.updateStatsUser(message.getGroupId(), userId,
                    serviceContext.getModifiedDate(now));
        }

        return message;
    }

    public void updateUserName(long userId, String userName) throws SystemException {

        List<MBMessage> messages = mbMessagePersistence.findByUserId(userId);

        for (MBMessage message : messages) {
            message.setUserName(userName);

            mbMessagePersistence.update(message, false);
        }
    }

    protected void deleteDiscussionSocialActivities(String className, MBMessage message)
            throws PortalException, SystemException {

        MBDiscussion discussion = mbDiscussionPersistence.findByThreadId(message.getThreadId());

        long classNameId = PortalUtil.getClassNameId(className);
        long classPK = discussion.getClassPK();

        if (discussion.getClassNameId() != classNameId) {
            return;
        }

        List<SocialActivity> socialActivities = socialActivityLocalService.getActivities(0, className, classPK,
                QueryUtil.ALL_POS, QueryUtil.ALL_POS);

        for (SocialActivity socialActivity : socialActivities) {
            if (Validator.isNull(socialActivity.getExtraData())) {
                continue;
            }

            JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(socialActivity.getExtraData());

            long extraDataMessageId = extraDataJSONObject.getLong("messageId");

            if (message.getMessageId() == extraDataMessageId) {
                socialActivityLocalService.deleteActivity(socialActivity.getActivityId());
            }
        }
    }

    protected String getBody(String subject, String body) {
        if (Validator.isNull(body)) {
            return subject;
        }

        return body;
    }

    protected String getSubject(String subject, String body) {
        if (Validator.isNull(subject)) {
            return StringUtil.shorten(body);
        }

        return subject;
    }

    protected void notifyDiscussionSubscribers(MBMessage message, ServiceContext serviceContext)
            throws SystemException {

        if (!PrefsPropsUtil.getBoolean(message.getCompanyId(), PropsKeys.DISCUSSION_EMAIL_COMMENTS_ADDED_ENABLED)) {

            return;
        }

        String contentURL = (String) serviceContext.getAttribute("contentURL");

        String userAddress = StringPool.BLANK;
        String userName = (String) serviceContext.getAttribute("pingbackUserName");

        if (Validator.isNull(userName)) {
            userAddress = PortalUtil.getUserEmailAddress(message.getUserId());
            userName = PortalUtil.getUserName(message.getUserId(), StringPool.BLANK);
        }

        String fromName = PrefsPropsUtil.getString(message.getCompanyId(), PropsKeys.ADMIN_EMAIL_FROM_NAME);
        String fromAddress = PrefsPropsUtil.getString(message.getCompanyId(), PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);

        String subject = PrefsPropsUtil.getContent(message.getCompanyId(), PropsKeys.DISCUSSION_EMAIL_SUBJECT);
        String body = PrefsPropsUtil.getContent(message.getCompanyId(), PropsKeys.DISCUSSION_EMAIL_BODY);

        SubscriptionSender subscriptionSender = new SubscriptionSender();

        subscriptionSender.setBody(body);
        subscriptionSender.setCompanyId(message.getCompanyId());
        subscriptionSender.setContextAttributes("[$COMMENTS_BODY$]", message.getBody(true),
                "[$COMMENTS_USER_ADDRESS$]", userAddress, "[$COMMENTS_USER_NAME$]", userName, "[$CONTENT_URL$]",
                contentURL);
        subscriptionSender.setFrom(fromAddress, fromName);
        subscriptionSender.setHtmlFormat(true);
        subscriptionSender.setMailId("mb_discussion", message.getCategoryId(), message.getMessageId());
        subscriptionSender.setScopeGroupId(message.getGroupId());
        subscriptionSender.setServiceContext(serviceContext);
        subscriptionSender.setSubject(subject);
        subscriptionSender.setUserId(message.getUserId());

        String className = (String) serviceContext.getAttribute("className");
        long classPK = GetterUtil.getLong((String) serviceContext.getAttribute("classPK"));

        subscriptionSender.addPersistedSubscribers(className, classPK);

        subscriptionSender.flushNotificationsAsync();
    }

    protected void notifySubscribers(MBMessage message, ServiceContext serviceContext)
            throws PortalException, SystemException {

        String layoutFullURL = serviceContext.getLayoutFullURL();

        if (!message.isApproved() || Validator.isNull(layoutFullURL)) {
            return;
        }

        if (message.isDiscussion()) {
            try {
                notifyDiscussionSubscribers(message, serviceContext);
            } catch (Exception e) {
                _log.error(e, e);
            }

            return;
        }

        PortletPreferences preferences = ServiceContextUtil.getPortletPreferences(serviceContext);

        if (preferences == null) {
            long ownerId = message.getGroupId();
            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
            long plid = PortletKeys.PREFS_PLID_SHARED;
            String portletId = PortletKeys.MESSAGE_BOARDS;
            String defaultPreferences = null;

            preferences = portletPreferencesLocalService.getPreferences(message.getCompanyId(), ownerId, ownerType,
                    plid, portletId, defaultPreferences);
        }

        boolean update = GetterUtil.getBoolean((String) serviceContext.getAttribute("update"));

        if (!update && MBUtil.getEmailMessageAddedEnabled(preferences)) {
        } else if (update && MBUtil.getEmailMessageUpdatedEnabled(preferences)) {
        } else {
            return;
        }

        Company company = companyPersistence.findByPrimaryKey(message.getCompanyId());

        Group group = groupPersistence.findByPrimaryKey(message.getGroupId());

        String emailAddress = PortalUtil.getUserEmailAddress(message.getUserId());
        String fullName = PortalUtil.getUserName(message.getUserId(), message.getUserName());

        if (message.isAnonymous()) {
            emailAddress = StringPool.BLANK;
            fullName = serviceContext.translate("anonymous");
        }

        MBCategory category = message.getCategory();

        String categoryName = category.getName();

        if (category.getCategoryId() == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {

            categoryName = serviceContext.translate("message-boards-home");

            categoryName += " - " + group.getDescriptiveName();
        }

        List<Long> categoryIds = new ArrayList<Long>();

        categoryIds.add(message.getCategoryId());

        if ((message.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
                && (message.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {

            categoryIds.addAll(category.getAncestorCategoryIds());
        }

        String messageURL = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "message_boards/view_message/"
                + message.getMessageId();

        String fromName = MBUtil.getEmailFromName(preferences, message.getCompanyId());
        String fromAddress = MBUtil.getEmailFromAddress(preferences, message.getCompanyId());

        String mailingListAddress = StringPool.BLANK;

        if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
            mailingListAddress = MBUtil.getMailingListAddress(message.getGroupId(), message.getCategoryId(),
                    message.getMessageId(), company.getMx(), fromAddress);
        }

        String subjectPrefix = null;
        String body = null;
        String signature = null;

        if (update) {
            subjectPrefix = MBUtil.getEmailMessageUpdatedSubjectPrefix(preferences);
            body = MBUtil.getEmailMessageUpdatedBody(preferences);
            signature = MBUtil.getEmailMessageUpdatedSignature(preferences);
        } else {
            subjectPrefix = MBUtil.getEmailMessageAddedSubjectPrefix(preferences);
            body = MBUtil.getEmailMessageAddedBody(preferences);
            signature = MBUtil.getEmailMessageAddedSignature(preferences);
        }

        String subject = message.getSubject();

        if (!subjectPrefix.contains("[$MESSAGE_SUBJECT$]")) {
            subject = subjectPrefix.trim() + " " + subject.trim();
        }

        if (Validator.isNotNull(signature)) {
            body += "\n--\n" + signature;
        }

        String messageBody = message.getBody();

        boolean htmlFormat = MBUtil.getEmailHtmlFormat(preferences);

        if (htmlFormat) {
            try {
                messageBody = BBCodeTranslatorUtil.getHTML(messageBody);
            } catch (Exception e) {
                _log.error("Could not parse message " + message.getMessageId() + " " + e.getMessage());
            }
        }

        String inReplyTo = null;

        if (message.getParentMessageId() != MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {

            inReplyTo = PortalUtil.getMailId(company.getMx(), MBUtil.MESSAGE_POP_PORTLET_PREFIX,
                    message.getCategoryId(), message.getParentMessageId());
        }

        SubscriptionSender subscriptionSenderPrototype = new MBSubscriptionSender();

        subscriptionSenderPrototype.setBody(body);
        subscriptionSenderPrototype.setBulk(true);
        subscriptionSenderPrototype.setCompanyId(message.getCompanyId());
        subscriptionSenderPrototype.setContextAttribute("[$MESSAGE_BODY$]", messageBody, false);
        subscriptionSenderPrototype.setContextAttributes("[$CATEGORY_NAME$]", categoryName,
                "[$MAILING_LIST_ADDRESS$]", mailingListAddress, "[$MESSAGE_ID$]", message.getMessageId(),
                "[$MESSAGE_SUBJECT$]", message.getSubject(), "[$MESSAGE_URL$]", messageURL,
                "[$MESSAGE_USER_ADDRESS$]", emailAddress, "[$MESSAGE_USER_NAME$]", fullName);
        subscriptionSenderPrototype.setFrom(fromAddress, fromName);
        subscriptionSenderPrototype.setHtmlFormat(htmlFormat);
        subscriptionSenderPrototype.setInReplyTo(inReplyTo);
        subscriptionSenderPrototype.setMailId(MBUtil.MESSAGE_POP_PORTLET_PREFIX, message.getCategoryId(),
                message.getMessageId());
        subscriptionSenderPrototype.setPortletId(PortletKeys.MESSAGE_BOARDS);
        subscriptionSenderPrototype.setReplyToAddress(mailingListAddress);
        subscriptionSenderPrototype.setScopeGroupId(message.getGroupId());
        subscriptionSenderPrototype.setServiceContext(serviceContext);
        subscriptionSenderPrototype.setSubject(message.getSubject());
        subscriptionSenderPrototype.setUserId(message.getUserId());

        SubscriptionSender subscriptionSender = (SubscriptionSender) SerializableUtil
                .clone(subscriptionSenderPrototype);

        for (long categoryId : categoryIds) {
            if (categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
                categoryId = message.getGroupId();
            }

            subscriptionSender.addPersistedSubscribers(MBCategory.class.getName(), categoryId);
        }

        subscriptionSender.addPersistedSubscribers(MBThread.class.getName(), message.getThreadId());

        subscriptionSender.flushNotificationsAsync();

        if (!MailingListThreadLocal.isSourceMailingList()) {
            for (long categoryId : categoryIds) {
                MBSubscriptionSender sourceMailingListSubscriptionSender = (MBSubscriptionSender) SerializableUtil
                        .clone(subscriptionSenderPrototype);

                sourceMailingListSubscriptionSender.setBulk(false);

                sourceMailingListSubscriptionSender.addMailingListSubscriber(message.getGroupId(), categoryId);

                sourceMailingListSubscriptionSender.flushNotificationsAsync();
            }
        }
    }

    protected void pingPingback(MBMessage message, ServiceContext serviceContext) {

        if (!PropsValues.BLOGS_PINGBACK_ENABLED || !message.isAllowPingbacks() || !message.isApproved()) {

            return;
        }

        String layoutFullURL = serviceContext.getLayoutFullURL();

        if (Validator.isNull(layoutFullURL)) {
            return;
        }

        String sourceUri = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "message_boards/view_message/"
                + message.getMessageId();

        Source source = new Source(message.getBody(true));

        List<StartTag> startTags = source.getAllStartTags("a");

        for (StartTag startTag : startTags) {
            String targetUri = startTag.getAttributeValue("href");

            if (Validator.isNotNull(targetUri)) {
                try {
                    LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
                } catch (Exception e) {
                    _log.error("Error while sending pingback " + targetUri, e);
                }
            }
        }
    }

    protected void updateAsset(long userId, MBMessage message, long[] assetCategoryIds, String[] assetTagNames,
            long[] assetLinkEntryIds, boolean assetEntryVisible) throws PortalException, SystemException {

        boolean visible = false;

        if (assetEntryVisible && message.isApproved()
                && ((message.getClassNameId() == 0) || (message.getParentMessageId() != 0))) {

            visible = true;
        }

        AssetEntry assetEntry = assetEntryLocalService.updateEntry(userId, message.getGroupId(),
                message.getWorkflowClassName(), message.getMessageId(), message.getUuid(), 0, assetCategoryIds,
                assetTagNames, visible, null, null, null, null, ContentTypes.TEXT_HTML, message.getSubject(), null,
                null, null, null, 0, 0, null, false);

        assetLinkLocalService.updateLinks(userId, assetEntry.getEntryId(), assetLinkEntryIds,
                AssetLinkConstants.TYPE_RELATED);
    }

    protected void updatePriorities(long threadId, double priority) throws SystemException {

        List<MBMessage> messages = mbMessagePersistence.findByThreadId(threadId);

        for (MBMessage message : messages) {
            if (message.getPriority() != priority) {
                message.setPriority(priority);

                mbMessagePersistence.update(message, false);
            }
        }
    }

    protected void validate(String subject, String body) throws PortalException {

        if (Validator.isNull(subject) && Validator.isNull(body)) {
            throw new MessageSubjectException();
        }
    }

    private static Log _log = LogFactoryUtil.getLog(MBMessageLocalServiceImpl.class);

}