001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.messageboards.service.impl;
016    
017    import com.liferay.documentlibrary.DuplicateDirectoryException;
018    import com.liferay.documentlibrary.DuplicateFileException;
019    import com.liferay.documentlibrary.NoSuchDirectoryException;
020    import com.liferay.portal.NoSuchUserException;
021    import com.liferay.portal.kernel.dao.orm.QueryUtil;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.json.JSONFactoryUtil;
025    import com.liferay.portal.kernel.json.JSONObject;
026    import com.liferay.portal.kernel.language.LanguageUtil;
027    import com.liferay.portal.kernel.log.Log;
028    import com.liferay.portal.kernel.log.LogFactoryUtil;
029    import com.liferay.portal.kernel.mail.MailMessage;
030    import com.liferay.portal.kernel.messaging.DestinationNames;
031    import com.liferay.portal.kernel.messaging.MessageBusUtil;
032    import com.liferay.portal.kernel.search.Indexer;
033    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
034    import com.liferay.portal.kernel.util.ContentTypes;
035    import com.liferay.portal.kernel.util.GetterUtil;
036    import com.liferay.portal.kernel.util.ListUtil;
037    import com.liferay.portal.kernel.util.LocaleUtil;
038    import com.liferay.portal.kernel.util.ObjectValuePair;
039    import com.liferay.portal.kernel.util.OrderByComparator;
040    import com.liferay.portal.kernel.util.PropsKeys;
041    import com.liferay.portal.kernel.util.StringPool;
042    import com.liferay.portal.kernel.util.StringUtil;
043    import com.liferay.portal.kernel.util.Validator;
044    import com.liferay.portal.kernel.workflow.WorkflowConstants;
045    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
046    import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
047    import com.liferay.portal.model.Company;
048    import com.liferay.portal.model.CompanyConstants;
049    import com.liferay.portal.model.Group;
050    import com.liferay.portal.model.GroupConstants;
051    import com.liferay.portal.model.ModelHintsUtil;
052    import com.liferay.portal.model.ResourceConstants;
053    import com.liferay.portal.model.User;
054    import com.liferay.portal.security.auth.PrincipalException;
055    import com.liferay.portal.security.permission.ActionKeys;
056    import com.liferay.portal.service.ServiceContext;
057    import com.liferay.portal.service.ServiceContextUtil;
058    import com.liferay.portal.util.Portal;
059    import com.liferay.portal.util.PortalUtil;
060    import com.liferay.portal.util.PortletKeys;
061    import com.liferay.portal.util.PrefsPropsUtil;
062    import com.liferay.portal.util.PropsValues;
063    import com.liferay.portlet.blogs.model.BlogsEntry;
064    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
065    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
066    import com.liferay.portlet.expando.model.ExpandoBridge;
067    import com.liferay.portlet.messageboards.MessageBodyException;
068    import com.liferay.portlet.messageboards.MessageSubjectException;
069    import com.liferay.portlet.messageboards.NoSuchDiscussionException;
070    import com.liferay.portlet.messageboards.RequiredMessageException;
071    import com.liferay.portlet.messageboards.model.MBCategory;
072    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
073    import com.liferay.portlet.messageboards.model.MBDiscussion;
074    import com.liferay.portlet.messageboards.model.MBMessage;
075    import com.liferay.portlet.messageboards.model.MBMessageConstants;
076    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
077    import com.liferay.portlet.messageboards.model.MBThread;
078    import com.liferay.portlet.messageboards.model.MBThreadConstants;
079    import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
080    import com.liferay.portlet.messageboards.model.impl.MBMessageDisplayImpl;
081    import com.liferay.portlet.messageboards.service.base.MBMessageLocalServiceBaseImpl;
082    import com.liferay.portlet.messageboards.social.MBActivityKeys;
083    import com.liferay.portlet.messageboards.util.MBUtil;
084    import com.liferay.portlet.messageboards.util.MailingListThreadLocal;
085    import com.liferay.portlet.messageboards.util.comparator.MessageThreadComparator;
086    import com.liferay.portlet.messageboards.util.comparator.ThreadLastPostDateComparator;
087    import com.liferay.portlet.social.model.SocialActivity;
088    
089    import java.io.IOException;
090    
091    import java.util.ArrayList;
092    import java.util.Comparator;
093    import java.util.Date;
094    import java.util.HashSet;
095    import java.util.Iterator;
096    import java.util.List;
097    import java.util.Set;
098    
099    import javax.mail.internet.InternetAddress;
100    
101    import javax.portlet.PortletPreferences;
102    
103    import net.htmlparser.jericho.Source;
104    import net.htmlparser.jericho.StartTag;
105    
106    /**
107     * @author Brian Wing Shun Chan
108     * @author Raymond Augé
109     * @author Mika Koivisto
110     * @author Jorge Ferrer
111     */
112    public class MBMessageLocalServiceImpl extends MBMessageLocalServiceBaseImpl {
113    
114            public MBMessage addDiscussionMessage(
115                            long userId, String userName, long groupId, String className,
116                            long classPK, int workflowAction)
117                    throws PortalException, SystemException {
118    
119                    long threadId = 0;
120                    long parentMessageId = 0;
121                    String subject = String.valueOf(classPK);
122                    String body = subject;
123    
124                    ServiceContext serviceContext = new ServiceContext();
125    
126                    serviceContext.setWorkflowAction(workflowAction);
127    
128                    boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
129    
130                    WorkflowThreadLocal.setEnabled(false);
131    
132                    try {
133                            return addDiscussionMessage(
134                                    userId, userName, groupId, className, classPK, threadId,
135                                    parentMessageId, subject, body, serviceContext);
136                    }
137                    finally {
138                            WorkflowThreadLocal.setEnabled(workflowEnabled);
139                    }
140            }
141    
142            public MBMessage addDiscussionMessage(
143                            long userId, String userName, long groupId, String className,
144                            long classPK, long threadId, long parentMessageId, String subject,
145                            String body, ServiceContext serviceContext)
146                    throws PortalException, SystemException {
147    
148                    // Message
149    
150                    long categoryId = MBCategoryConstants.DISCUSSION_CATEGORY_ID;
151    
152                    if (Validator.isNull(subject)) {
153                            subject = body.substring(0, Math.min(body.length(), 50)) + "...";
154                    }
155    
156                    List<ObjectValuePair<String, byte[]>> files =
157                            new ArrayList<ObjectValuePair<String, byte[]>>();
158                    boolean anonymous = false;
159                    double priority = 0.0;
160                    boolean allowPingbacks = false;
161    
162                    serviceContext.setAddCommunityPermissions(true);
163                    serviceContext.setAddGuestPermissions(true);
164                    serviceContext.setAttribute("className", className);
165                    serviceContext.setAttribute("classPK", String.valueOf(classPK));
166    
167                    MBMessage message = addMessage(
168                            userId, userName, groupId, categoryId, threadId, parentMessageId,
169                            subject, body, files, anonymous, priority, allowPingbacks,
170                            serviceContext);
171    
172                    // Discussion
173    
174                    if (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
175                            long classNameId = PortalUtil.getClassNameId(className);
176    
177                            MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
178                                    classNameId, classPK);
179    
180                            if (discussion == null) {
181                                    discussion = mbDiscussionLocalService.addDiscussion(
182                                            classNameId, classPK, message.getThreadId());
183                            }
184                    }
185    
186                    return message;
187            }
188    
189            public MBMessage addMessage(
190                            long userId, String userName, long groupId, long categoryId,
191                            long threadId, long parentMessageId, String subject, String body,
192                            List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
193                            double priority, boolean allowPingbacks,
194                            ServiceContext serviceContext)
195                    throws PortalException, SystemException {
196    
197                    // Message
198    
199                    User user = userPersistence.findByPrimaryKey(userId);
200                    userName = user.isDefaultUser() ? userName : user.getFullName();
201                    subject = ModelHintsUtil.trimString(
202                            MBMessage.class.getName(), "subject", subject);
203    
204                    PortletPreferences preferences =
205                            ServiceContextUtil.getPortletPreferences(serviceContext);
206    
207                    if (preferences != null) {
208                            if (!MBUtil.isAllowAnonymousPosting(preferences)) {
209                                    if (anonymous || user.isDefaultUser()) {
210                                            throw new PrincipalException();
211                                    }
212                            }
213                    }
214    
215                    if (user.isDefaultUser()) {
216                            anonymous = true;
217                    }
218    
219                    Date now = new Date();
220    
221                    validate(subject, body);
222    
223                    long messageId = counterLocalService.increment();
224    
225                    MBMessage message = mbMessagePersistence.create(messageId);
226    
227                    message.setUuid(serviceContext.getUuid());
228                    message.setGroupId(groupId);
229                    message.setCompanyId(user.getCompanyId());
230                    message.setUserId(user.getUserId());
231                    message.setUserName(userName);
232                    message.setCreateDate(serviceContext.getCreateDate(now));
233                    message.setModifiedDate(serviceContext.getModifiedDate(now));
234                    message.setAllowPingbacks(allowPingbacks);
235                    message.setStatus(WorkflowConstants.STATUS_DRAFT);
236                    message.setStatusByUserId(user.getUserId());
237                    message.setStatusByUserName(userName);
238                    message.setStatusDate(serviceContext.getModifiedDate(now));
239    
240                    // Thread
241    
242                    if (parentMessageId != MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
243                            MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(
244                                    parentMessageId);
245    
246                            if (parentMessage == null) {
247                                    parentMessageId = MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID;
248                            }
249                    }
250    
251                    MBThread thread = null;
252    
253                    if (threadId > 0) {
254                            thread = mbThreadPersistence.fetchByPrimaryKey(threadId);
255                    }
256    
257                    if ((thread == null) ||
258                            (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID)) {
259    
260                            threadId = counterLocalService.increment();
261    
262                            thread = mbThreadPersistence.create(threadId);
263    
264                            thread.setGroupId(groupId);
265                            thread.setCategoryId(categoryId);
266                            thread.setRootMessageId(messageId);
267                            thread.setStatus(WorkflowConstants.STATUS_DRAFT);
268                            thread.setStatusByUserId(user.getUserId());
269                            thread.setStatusByUserName(userName);
270                            thread.setStatusDate(serviceContext.getModifiedDate(now));
271                    }
272    
273                    if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) &&
274                            (thread.getPriority() != priority)) {
275    
276                            thread.setPriority(priority);
277    
278                            updatePriorities(thread.getThreadId(), priority);
279                    }
280    
281                    // Message
282    
283                    message.setCategoryId(categoryId);
284                    message.setThreadId(threadId);
285                    message.setRootMessageId(thread.getRootMessageId());
286                    message.setParentMessageId(parentMessageId);
287                    message.setSubject(subject);
288                    message.setBody(body);
289                    message.setAttachments(!files.isEmpty());
290                    message.setAnonymous(anonymous);
291    
292                    if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
293                            message.setPriority(priority);
294                    }
295    
296                    if (message.isDiscussion()) {
297                            long classNameId = PortalUtil.getClassNameId(
298                                    (String)serviceContext.getAttribute("className"));
299                            long classPK = GetterUtil.getLong(
300                                    (String)serviceContext.getAttribute("classPK"));
301    
302                            message.setClassNameId(classNameId);
303                            message.setClassPK(classPK);
304                    }
305    
306                    // Attachments
307    
308                    if (files.size() > 0) {
309                            long companyId = message.getCompanyId();
310                            String portletId = CompanyConstants.SYSTEM_STRING;
311                            long dlGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
312                            long repositoryId = CompanyConstants.SYSTEM;
313                            String dirName = message.getAttachmentsDir();
314    
315                            try {
316                                    dlService.deleteDirectory(
317                                            companyId, portletId, repositoryId, dirName);
318                            }
319                            catch (NoSuchDirectoryException nsde) {
320                                    if (_log.isDebugEnabled()) {
321                                            _log.debug(nsde.getMessage());
322                                    }
323                            }
324    
325                            dlService.addDirectory(companyId, repositoryId, dirName);
326    
327                            for (int i = 0; i < files.size(); i++) {
328                                    ObjectValuePair<String, byte[]> ovp = files.get(i);
329    
330                                    String fileName = ovp.getKey();
331                                    byte[] bytes = ovp.getValue();
332    
333                                    try {
334                                            dlService.addFile(
335                                                    companyId, portletId, dlGroupId, repositoryId,
336                                                    dirName + "/" + fileName, 0, StringPool.BLANK,
337                                                    message.getModifiedDate(), new ServiceContext(), bytes);
338                                    }
339                                    catch (DuplicateFileException dfe) {
340                                            if (_log.isDebugEnabled()) {
341                                                    _log.debug(dfe.getMessage());
342                                            }
343                                    }
344                            }
345                    }
346    
347                    // Commit
348    
349                    mbThreadPersistence.update(thread, false);
350                    mbMessagePersistence.update(message, false);
351    
352                    // Resources
353    
354                    if (!message.isDiscussion()) {
355                            if (user.isDefaultUser()) {
356                                    addMessageResources(message, true, true);
357                            }
358                            if (serviceContext.getAddCommunityPermissions() ||
359                                    serviceContext.getAddGuestPermissions()) {
360    
361                                    addMessageResources(
362                                            message, serviceContext.getAddCommunityPermissions(),
363                                            serviceContext.getAddGuestPermissions());
364                            }
365                            else {
366                                    addMessageResources(
367                                            message, serviceContext.getCommunityPermissions(),
368                                            serviceContext.getGuestPermissions());
369                            }
370                    }
371    
372                    // Asset
373    
374                    updateAsset(
375                            userId, message, serviceContext.getAssetCategoryIds(),
376                            serviceContext.getAssetTagNames());
377    
378                    // Expando
379    
380                    ExpandoBridge expandoBridge = message.getExpandoBridge();
381    
382                    expandoBridge.setAttributes(serviceContext);
383    
384                    // Workflow
385    
386                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
387                            user.getCompanyId(), groupId, userId,
388                            message.getWorkflowClassName(), message.getMessageId(), message,
389                            serviceContext);
390    
391                    // Testing roll back
392    
393                    /*if (true) {
394                            throw new SystemException("Testing roll back");
395                    }*/
396    
397                    return message;
398            }
399    
400            public MBMessage addMessage(
401                            long userId, String userName, long groupId, long categoryId,
402                            String subject, String body,
403                            List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
404                            double priority, boolean allowPingbacks,
405                            ServiceContext serviceContext)
406                    throws PortalException, SystemException {
407    
408                    long threadId = 0;
409                    long parentMessageId = 0;
410    
411                    return addMessage(
412                            userId, userName, groupId, categoryId, threadId, parentMessageId,
413                            subject, body, files, anonymous, priority, allowPingbacks,
414                            serviceContext);
415            }
416    
417            public void addMessageResources(
418                            long messageId, boolean addCommunityPermissions,
419                            boolean addGuestPermissions)
420                    throws PortalException, SystemException {
421    
422                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
423    
424                    addMessageResources(
425                            message, addCommunityPermissions, addGuestPermissions);
426            }
427    
428            public void addMessageResources(
429                            long messageId, String[] communityPermissions,
430                            String[] guestPermissions)
431                    throws PortalException, SystemException {
432    
433                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
434    
435                    addMessageResources(message, communityPermissions, guestPermissions);
436            }
437    
438            public void addMessageResources(
439                            MBMessage message, boolean addCommunityPermissions,
440                            boolean addGuestPermissions)
441                    throws PortalException, SystemException {
442    
443                    resourceLocalService.addResources(
444                            message.getCompanyId(), message.getGroupId(), message.getUserId(),
445                            MBMessage.class.getName(), message.getMessageId(),
446                            false, addCommunityPermissions, addGuestPermissions);
447            }
448    
449            public void addMessageResources(
450                            MBMessage message, String[] communityPermissions,
451                            String[] guestPermissions)
452                    throws PortalException, SystemException {
453    
454                    resourceLocalService.addModelResources(
455                            message.getCompanyId(), message.getGroupId(), message.getUserId(),
456                            MBMessage.class.getName(), message.getMessageId(),
457                            communityPermissions, guestPermissions);
458            }
459    
460            public void deleteDiscussionMessage(long messageId)
461                    throws PortalException, SystemException {
462    
463                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
464    
465                    List<MBMessage> messages = new ArrayList<MBMessage>();
466    
467                    messages.add(message);
468    
469                    deleteDiscussionSocialActivities(BlogsEntry.class.getName(), messages);
470    
471                    deleteMessage(message);
472            }
473    
474            public void deleteDiscussionMessages(String className, long classPK)
475                    throws PortalException, SystemException {
476    
477                    try {
478                            long classNameId = PortalUtil.getClassNameId(className);
479    
480                            MBDiscussion discussion = mbDiscussionPersistence.findByC_C(
481                                    classNameId, classPK);
482    
483                            List<MBMessage> messages = mbMessagePersistence.findByT_P(
484                                    discussion.getThreadId(),
485                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, 0, 1);
486    
487                            deleteDiscussionSocialActivities(
488                                    BlogsEntry.class.getName(), messages);
489    
490                            if (messages.size() > 0) {
491                                    MBMessage message = messages.get(0);
492    
493                                    mbThreadLocalService.deleteThread(message.getThreadId());
494                            }
495    
496                            mbDiscussionPersistence.remove(discussion);
497                    }
498                    catch (NoSuchDiscussionException nsde) {
499                            if (_log.isDebugEnabled()) {
500                                    _log.debug(nsde.getMessage());
501                            }
502                    }
503            }
504    
505            public void deleteMessage(long messageId)
506                    throws PortalException, SystemException {
507    
508                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
509    
510                    deleteMessage(message);
511            }
512    
513            public void deleteMessage(MBMessage message)
514                    throws PortalException, SystemException {
515    
516                    // Indexer
517    
518                    Indexer indexer = IndexerRegistryUtil.getIndexer(MBMessage.class);
519    
520                    indexer.delete(message);
521    
522                    // Attachments
523    
524                    if (message.isAttachments()) {
525                            long companyId = message.getCompanyId();
526                            String portletId = CompanyConstants.SYSTEM_STRING;
527                            long repositoryId = CompanyConstants.SYSTEM;
528                            String dirName = message.getAttachmentsDir();
529    
530                            try {
531                                    dlService.deleteDirectory(
532                                            companyId, portletId, repositoryId, dirName);
533                            }
534                            catch (NoSuchDirectoryException nsde) {
535                                    if (_log.isDebugEnabled()) {
536                                            _log.debug(nsde.getMessage());
537                                    }
538                            }
539                    }
540    
541                    // Thread
542    
543                    int count = mbMessagePersistence.countByThreadId(message.getThreadId());
544    
545                    // Message flags
546    
547                    if (message.isRoot()) {
548                            mbMessageFlagLocalService.deleteQuestionAndAnswerFlags(
549                                    message.getThreadId());
550                    }
551                    else if (mbMessageFlagLocalService.hasAnswerFlag(
552                                            message.getMessageId())) {
553    
554                            mbMessageFlagService.deleteAnswerFlag(message.getMessageId());
555                    }
556    
557                    if (count == 1) {
558    
559                            // Attachments
560    
561                            long companyId = message.getCompanyId();
562                            String portletId = CompanyConstants.SYSTEM_STRING;
563                            long repositoryId = CompanyConstants.SYSTEM;
564                            String dirName = message.getThreadAttachmentsDir();
565    
566                            try {
567                                    dlService.deleteDirectory(
568                                            companyId, portletId, repositoryId, dirName);
569                            }
570                            catch (NoSuchDirectoryException nsde) {
571                                    if (_log.isDebugEnabled()) {
572                                            _log.debug(nsde.getMessage());
573                                    }
574                            }
575    
576                            // Subscriptions
577    
578                            subscriptionLocalService.deleteSubscriptions(
579                                    message.getCompanyId(), MBThread.class.getName(),
580                                    message.getThreadId());
581    
582                            // Thread
583    
584                            mbThreadPersistence.remove(message.getThreadId());
585    
586                            // Category
587    
588                            if (!MBUtil.isDefaultParentCategoryId(message.getCategoryId()) &&
589                                    !MBUtil.isDiscussionCategoryId(message.getCategoryId())) {
590    
591                                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
592                                            message.getCategoryId());
593    
594                                    category.setThreadCount(category.getThreadCount() - 1);
595                                    category.setMessageCount(category.getMessageCount() - 1);
596    
597                                    mbCategoryPersistence.update(category, false);
598                            }
599                    }
600                    else if (count > 1) {
601                            MBThread thread = mbThreadPersistence.findByPrimaryKey(
602                                    message.getThreadId());
603    
604                            // Message is a root message
605    
606                            if (thread.getRootMessageId() == message.getMessageId()) {
607                                    List<MBMessage> childrenMessages =
608                                            mbMessagePersistence.findByT_P(
609                                                    message.getThreadId(), message.getMessageId());
610    
611                                    if (childrenMessages.size() > 1) {
612                                            throw new RequiredMessageException(
613                                                    String.valueOf(message.getMessageId()));
614                                    }
615                                    else if (childrenMessages.size() == 1) {
616                                            MBMessage childMessage = childrenMessages.get(0);
617    
618                                            childMessage.setRootMessageId(childMessage.getMessageId());
619                                            childMessage.setParentMessageId(
620                                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
621    
622                                            mbMessagePersistence.update(childMessage, false);
623    
624                                            thread.setRootMessageId(childMessage.getMessageId());
625    
626                                            mbThreadPersistence.update(thread, false);
627                                    }
628                            }
629    
630                            // Message is a child message
631    
632                            else {
633                                    List<MBMessage> childrenMessages =
634                                            mbMessagePersistence.findByT_P(
635                                                    message.getThreadId(), message.getMessageId());
636    
637                                    // Message has children messages
638    
639                                    if (childrenMessages.size() > 0) {
640                                            Iterator<MBMessage> itr = childrenMessages.iterator();
641    
642                                            while (itr.hasNext()) {
643                                                    MBMessage childMessage = itr.next();
644    
645                                                    childMessage.setParentMessageId(
646                                                            message.getParentMessageId());
647    
648                                                    mbMessagePersistence.update(childMessage, false);
649                                            }
650                                    }
651                            }
652    
653                            // Thread
654    
655                            thread.setMessageCount(count - 1);
656    
657                            mbThreadPersistence.update(thread, false);
658    
659                            // Category
660    
661                            if (!MBUtil.isDefaultParentCategoryId(message.getCategoryId()) &&
662                                    !MBUtil.isDiscussionCategoryId(message.getCategoryId())) {
663    
664                                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
665                                            message.getCategoryId());
666    
667                                    category.setMessageCount(category.getMessageCount() - 1);
668    
669                                    mbCategoryPersistence.update(category, false);
670                            }
671                    }
672    
673                    // Asset
674    
675                    assetEntryLocalService.deleteEntry(
676                            MBMessage.class.getName(), message.getMessageId());
677    
678                    // Expando
679    
680                    expandoValueLocalService.deleteValues(
681                            MBMessage.class.getName(), message.getMessageId());
682    
683                    // Social
684    
685                    socialActivityLocalService.deleteActivities(
686                            MBMessage.class.getName(), message.getMessageId());
687    
688                    // Ratings
689    
690                    ratingsStatsLocalService.deleteStats(
691                            MBMessage.class.getName(), message.getMessageId());
692    
693                    // Statistics
694    
695                    if (!message.isDiscussion()) {
696                            mbStatsUserLocalService.updateStatsUser(
697                                    message.getGroupId(), message.getUserId());
698                    }
699    
700                    // Message flags
701    
702                    mbMessageFlagPersistence.removeByMessageId(message.getMessageId());
703    
704                    // Resources
705    
706                    if (!message.isDiscussion()) {
707                            resourceLocalService.deleteResource(
708                                    message.getCompanyId(), MBMessage.class.getName(),
709                                    ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
710                    }
711    
712                    // Message
713    
714                    mbMessagePersistence.remove(message);
715    
716                    // Workflow
717    
718                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
719                            message.getCompanyId(), message.getGroupId(),
720                            message.getWorkflowClassName(), message.getMessageId());
721            }
722    
723            public List<MBMessage> getCategoryMessages(
724                            long groupId, long categoryId, int status, int start, int end)
725                    throws SystemException {
726    
727                    if (status == WorkflowConstants.STATUS_ANY) {
728                            return mbMessagePersistence.findByG_C(
729                                    groupId, categoryId, start, end);
730                    }
731                    else {
732                            return mbMessagePersistence.findByG_C_S(
733                                    groupId, categoryId, status, start, end);
734                    }
735            }
736    
737            public List<MBMessage> getCategoryMessages(
738                            long groupId, long categoryId, int status, int start, int end,
739                            OrderByComparator obc)
740                    throws SystemException {
741    
742                    if (status == WorkflowConstants.STATUS_ANY) {
743                            return mbMessagePersistence.findByG_C(
744                                    groupId, categoryId, start, end, obc);
745                    }
746                    else {
747                            return mbMessagePersistence.findByG_C_S(
748                                    groupId, categoryId, status, start, end, obc);
749                    }
750            }
751    
752            public int getCategoryMessagesCount(
753                            long groupId, long categoryId, int status)
754                    throws SystemException {
755    
756                    if (status == WorkflowConstants.STATUS_ANY) {
757                            return mbMessagePersistence.countByG_C(groupId, categoryId);
758                    }
759                    else {
760                            return mbMessagePersistence.countByG_C_S(
761                                    groupId, categoryId, status);
762                    }
763            }
764    
765            public List<MBMessage> getCompanyMessages(
766                            long companyId, int status, int start, int end)
767                    throws SystemException {
768    
769                    if (status == WorkflowConstants.STATUS_ANY) {
770                            return mbMessagePersistence.findByCompanyId(companyId, start, end);
771                    }
772                    else {
773                            return mbMessagePersistence.findByC_S(
774                                    companyId, status, start, end);
775                    }
776            }
777    
778            public List<MBMessage> getCompanyMessages(
779                            long companyId, int status, int start, int end,
780                            OrderByComparator obc)
781                    throws SystemException {
782    
783                    if (status == WorkflowConstants.STATUS_ANY) {
784                            return mbMessagePersistence.findByCompanyId(
785                                    companyId, start, end, obc);
786                    }
787                    else {
788                            return mbMessagePersistence.findByC_S(
789                                    companyId, status, start, end, obc);
790                    }
791            }
792    
793            public int getCompanyMessagesCount(long companyId, int status)
794                    throws SystemException {
795    
796                    if (status == WorkflowConstants.STATUS_ANY) {
797                            return mbMessagePersistence.countByCompanyId(companyId);
798                    }
799                    else {
800                            return mbMessagePersistence.countByC_S(companyId, status);
801                    }
802            }
803    
804            public MBMessageDisplay getDiscussionMessageDisplay(
805                            long userId, long groupId, String className, long classPK,
806                            int status)
807                    throws PortalException, SystemException {
808    
809                    return getDiscussionMessageDisplay(
810                            userId, groupId, className, classPK, status,
811                            MBThreadConstants.THREAD_VIEW_COMBINATION);
812            }
813    
814            public MBMessageDisplay getDiscussionMessageDisplay(
815                            long userId, long groupId, String className, long classPK,
816                            int status, String threadView)
817                    throws PortalException, SystemException {
818    
819                    long classNameId = PortalUtil.getClassNameId(className);
820    
821                    MBMessage message = null;
822    
823                    MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
824                            classNameId, classPK);
825    
826                    if (discussion != null) {
827                            List<MBMessage> messages = mbMessagePersistence.findByT_P(
828                                    discussion.getThreadId(),
829                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
830    
831                            message = messages.get(0);
832                    }
833                    else {
834                            boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
835    
836                            WorkflowThreadLocal.setEnabled(false);
837    
838                            try {
839                                    String subject = String.valueOf(classPK);
840                                    //String body = subject;
841    
842                                    message = addDiscussionMessage(
843                                            userId, null, groupId, className, classPK, 0,
844                                            MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, subject,
845                                            subject, new ServiceContext());
846                            }
847                            catch (SystemException se) {
848                                    if (_log.isWarnEnabled()) {
849                                            _log.warn(
850                                                    "Add failed, fetch {threadId=0, parentMessageId=" +
851                                                            MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID + "}");
852                                    }
853    
854                                    List<MBMessage> messages = mbMessagePersistence.findByT_P(
855                                            0, MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
856    
857                                    if (messages.isEmpty()) {
858                                            throw se;
859                                    }
860    
861                                    message = messages.get(0);
862                            }
863                            finally {
864                                    WorkflowThreadLocal.setEnabled(workflowEnabled);
865                            }
866                    }
867    
868                    return getMessageDisplay(message, status, threadView, false);
869            }
870    
871            public int getDiscussionMessagesCount(
872                            long classNameId, long classPK, int status)
873                    throws SystemException {
874    
875                    MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
876                            classNameId, classPK);
877    
878                    if (discussion == null) {
879                            return 0;
880                    }
881    
882                    int count = 0;
883    
884                    if (status == WorkflowConstants.STATUS_ANY) {
885                            count = mbMessagePersistence.countByThreadId(
886                                    discussion.getThreadId());
887                    }
888                    else {
889                            count = mbMessagePersistence.countByT_S(
890                                    discussion.getThreadId(), status);
891                    }
892    
893                    if (count >= 1) {
894                            return count - 1;
895                    }
896                    else {
897                            return 0;
898                    }
899            }
900    
901            public int getDiscussionMessagesCount(
902                            String className, long classPK, int status)
903                    throws SystemException {
904    
905                    long classNameId = PortalUtil.getClassNameId(className);
906    
907                    return getDiscussionMessagesCount(classNameId, classPK, status);
908            }
909    
910            public List<MBDiscussion> getDiscussions(String className)
911                    throws SystemException {
912    
913                    long classNameId = PortalUtil.getClassNameId(className);
914    
915                    return mbDiscussionPersistence.findByClassNameId(classNameId);
916            }
917    
918            public List<MBMessage> getGroupMessages(
919                            long groupId, int status, int start, int end)
920                    throws SystemException {
921    
922                    if (status == WorkflowConstants.STATUS_ANY) {
923                            return mbMessagePersistence.findByGroupId(groupId, start, end);
924                    }
925                    else {
926                            return mbMessagePersistence.findByG_S(groupId, status, start, end);
927                    }
928            }
929    
930            public List<MBMessage> getGroupMessages(
931                            long groupId, int status, int start, int end, OrderByComparator obc)
932                    throws SystemException {
933    
934                    if (status == WorkflowConstants.STATUS_ANY) {
935                            return mbMessagePersistence.findByGroupId(groupId, start, end, obc);
936                    }
937                    else {
938                            return mbMessagePersistence.findByG_S(
939                                    groupId, status, start, end, obc);
940                    }
941            }
942    
943            public List<MBMessage> getGroupMessages(
944                            long groupId, long userId, int status, int start, int end)
945                    throws SystemException {
946    
947                    if (status == WorkflowConstants.STATUS_ANY) {
948                            return mbMessagePersistence.findByG_U(groupId, userId, start, end);
949                    }
950                    else {
951                            return mbMessagePersistence.findByG_U_S(
952                                    groupId, userId, status, start, end);
953                    }
954            }
955    
956            public List<MBMessage> getGroupMessages(
957                            long groupId, long userId, int status, int start, int end,
958                            OrderByComparator obc)
959                    throws SystemException {
960    
961                    if (status == WorkflowConstants.STATUS_ANY) {
962                            return mbMessagePersistence.findByG_U(
963                                    groupId, userId, start, end, obc);
964                    }
965                    else {
966                            return mbMessagePersistence.findByG_U_S(
967                                    groupId, userId, status, start, end, obc);
968                    }
969            }
970    
971            public int getGroupMessagesCount(long groupId, int status)
972                    throws SystemException {
973    
974                    if (status == WorkflowConstants.STATUS_ANY) {
975                            return mbMessagePersistence.countByGroupId(groupId);
976                    }
977                    else {
978                            return mbMessagePersistence.countByG_S(groupId, status);
979                    }
980            }
981    
982            public int getGroupMessagesCount(long groupId, long userId, int status)
983                    throws SystemException {
984    
985                    if (status == WorkflowConstants.STATUS_ANY) {
986                            return mbMessagePersistence.countByG_U(groupId, userId);
987                    }
988                    else {
989                            return mbMessagePersistence.countByG_U_S(groupId, userId, status);
990                    }
991            }
992    
993            public MBMessage getMessage(long messageId)
994                    throws PortalException, SystemException {
995    
996                    return mbMessagePersistence.findByPrimaryKey(messageId);
997            }
998    
999            public MBMessageDisplay getMessageDisplay(
1000                            long messageId, int status, String threadView,
1001                            boolean includePrevAndNext)
1002                    throws PortalException, SystemException {
1003    
1004                    MBMessage message = getMessage(messageId);
1005    
1006                    return getMessageDisplay(
1007                            message, status, threadView, includePrevAndNext);
1008            }
1009    
1010            public MBMessageDisplay getMessageDisplay(
1011                            MBMessage message, int status, String threadView,
1012                            boolean includePrevAndNext)
1013                    throws PortalException, SystemException {
1014    
1015                    MBCategory category = null;
1016    
1017                    if (!MBUtil.isDefaultParentCategoryId(message.getCategoryId()) &&
1018                            !MBUtil.isDiscussionCategoryId(message.getCategoryId())) {
1019    
1020                            category = mbCategoryPersistence.findByPrimaryKey(
1021                                    message.getCategoryId());
1022                    }
1023                    else {
1024                            category = new MBCategoryImpl();
1025    
1026                            category.setCategoryId(message.getCategoryId());
1027                    }
1028    
1029                    MBMessage parentMessage = null;
1030    
1031                    if (message.isReply()) {
1032                            parentMessage = mbMessagePersistence.findByPrimaryKey(
1033                                    message.getParentMessageId());
1034                    }
1035    
1036                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1037                            message.getThreadId());
1038    
1039                    if (!message.isDiscussion() &&
1040                            (message.getStatus() == WorkflowConstants.STATUS_APPROVED)) {
1041    
1042                            mbThreadLocalService.updateThread(
1043                                    thread.getThreadId(), thread.getViewCount() + 1);
1044                    }
1045    
1046                    MBThread previousThread = null;
1047                    MBThread nextThread = null;
1048    
1049                    if ((message.getStatus() == WorkflowConstants.STATUS_APPROVED) &&
1050                            includePrevAndNext) {
1051    
1052                            ThreadLastPostDateComparator comparator =
1053                                    new ThreadLastPostDateComparator(false);
1054    
1055                            MBThread[] prevAndNextThreads =
1056                                    mbThreadPersistence.findByG_C_PrevAndNext(
1057                                            message.getThreadId(), message.getGroupId(),
1058                                            message.getCategoryId(), comparator);
1059    
1060                            previousThread = prevAndNextThreads[0];
1061                            nextThread = prevAndNextThreads[2];
1062                    }
1063    
1064                    return new MBMessageDisplayImpl(
1065                            message, parentMessage, category, thread,
1066                            previousThread, nextThread, status, threadView);
1067            }
1068    
1069            public List<MBMessage> getMessages(
1070                            String className, long classPK, int status)
1071                    throws SystemException {
1072    
1073                    long classNameId = PortalUtil.getClassNameId(className);
1074    
1075                    if (status == WorkflowConstants.STATUS_ANY) {
1076                            return mbMessagePersistence.findByC_C(classNameId, classPK);
1077                    }
1078                    else {
1079                            return mbMessagePersistence.findByC_C_S(
1080                                    classNameId, classPK, status);
1081                    }
1082            }
1083    
1084            public List<MBMessage> getNoAssetMessages() throws SystemException {
1085                    return mbMessageFinder.findByNoAssets();
1086            }
1087    
1088            public int getPositionInThread(long messageId)
1089                    throws PortalException, SystemException {
1090    
1091                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1092    
1093                    return mbMessageFinder.countByC_T(
1094                            message.getCreateDate(), message.getThreadId());
1095            }
1096    
1097            public List<MBMessage> getThreadMessages(long threadId, int status)
1098                    throws SystemException {
1099    
1100                    return getThreadMessages(
1101                            threadId, status, new MessageThreadComparator());
1102            }
1103    
1104            public List<MBMessage> getThreadMessages(
1105                            long threadId, int status, Comparator<MBMessage> comparator)
1106                    throws SystemException {
1107    
1108                    List<MBMessage> messages = null;
1109    
1110                    if (status == WorkflowConstants.STATUS_ANY) {
1111                            messages = mbMessagePersistence.findByThreadId(threadId);
1112                    }
1113                    else {
1114                            messages = mbMessagePersistence.findByT_S(threadId, status);
1115                    }
1116    
1117                    return ListUtil.sort(messages, comparator);
1118            }
1119    
1120            public List<MBMessage> getThreadMessages(
1121                            long threadId, int status, int start, int end)
1122                    throws SystemException {
1123    
1124                    if (status == WorkflowConstants.STATUS_ANY) {
1125                            return mbMessagePersistence.findByThreadId(threadId, start, end);
1126                    }
1127                    else {
1128                            return mbMessagePersistence.findByT_S(threadId, status, start, end);
1129                    }
1130            }
1131    
1132            public int getThreadMessagesCount(long threadId, int status)
1133                    throws SystemException {
1134    
1135                    if (status == WorkflowConstants.STATUS_ANY) {
1136                            return mbMessagePersistence.countByThreadId(threadId);
1137                    }
1138                    else {
1139                            return mbMessagePersistence.countByT_S(threadId, status);
1140                    }
1141            }
1142    
1143            public List<MBMessage> getThreadRepliesMessages(
1144                            long threadId, int status, int start, int end)
1145                    throws SystemException {
1146    
1147                    if (status == WorkflowConstants.STATUS_ANY) {
1148                            return mbMessagePersistence.findByThreadReplies(
1149                                    threadId, start, end);
1150                    }
1151                    else {
1152                            return mbMessagePersistence.findByTR_S(
1153                                    threadId, status, start, end);
1154                    }
1155            }
1156    
1157            public void subscribeMessage(long userId, long messageId)
1158                    throws PortalException, SystemException {
1159    
1160                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1161    
1162                    subscriptionLocalService.addSubscription(
1163                            userId, MBThread.class.getName(), message.getThreadId());
1164            }
1165    
1166            public void unsubscribeMessage(long userId, long messageId)
1167                    throws PortalException, SystemException {
1168    
1169                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1170    
1171                    subscriptionLocalService.deleteSubscription(
1172                            userId, MBThread.class.getName(), message.getThreadId());
1173            }
1174    
1175            public void updateAsset(
1176                            long userId, MBMessage message, long[] assetCategoryIds,
1177                            String[] assetTagNames)
1178                    throws PortalException, SystemException {
1179    
1180                    boolean visible = false;
1181    
1182                    if ((message.getStatus() == WorkflowConstants.STATUS_APPROVED) &&
1183                            ((message.getClassNameId() == 0) ||
1184                             (message.getParentMessageId() != 0))) {
1185    
1186                            visible = true;
1187                    }
1188    
1189                    assetEntryLocalService.updateEntry(
1190                            userId, message.getGroupId(), message.getWorkflowClassName(),
1191                            message.getMessageId(), message.getUuid(), assetCategoryIds,
1192                            assetTagNames, visible, null, null, null, null,
1193                            ContentTypes.TEXT_HTML, message.getSubject(), null, null, null, 0,
1194                            0, null, false);
1195            }
1196    
1197            public MBMessage updateDiscussionMessage(
1198                            long userId, long messageId, String subject, String body,
1199                            int workflowAction)
1200                    throws PortalException, SystemException {
1201    
1202                    if (Validator.isNull(subject)) {
1203                            subject = body.substring(0, Math.min(body.length(), 50)) + "...";
1204                    }
1205    
1206                    List<ObjectValuePair<String, byte[]>> files =
1207                            new ArrayList<ObjectValuePair<String, byte[]>>();
1208                    List<String> existingFiles = new ArrayList<String>();
1209                    double priority = 0.0;
1210                    boolean allowPingbacks = false;
1211    
1212                    ServiceContext serviceContext = new ServiceContext();
1213    
1214                    serviceContext.setWorkflowAction(workflowAction);
1215    
1216                    return updateMessage(
1217                            userId, messageId, subject, body, files, existingFiles, priority,
1218                            allowPingbacks, serviceContext);
1219            }
1220    
1221            public MBMessage updateMessage(
1222                            long userId, long messageId, String subject, String body,
1223                            List<ObjectValuePair<String, byte[]>> files,
1224                            List<String> existingFiles, double priority, boolean allowPingbacks,
1225                            ServiceContext serviceContext)
1226                    throws PortalException, SystemException {
1227    
1228                    // Message
1229    
1230                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1231    
1232                    subject = ModelHintsUtil.trimString(
1233                            MBMessage.class.getName(), "subject", subject);
1234                    Date now = new Date();
1235    
1236                    validate(subject, body);
1237    
1238                    message.setModifiedDate(serviceContext.getModifiedDate(now));
1239                    message.setSubject(subject);
1240                    message.setBody(body);
1241                    message.setAttachments(!files.isEmpty() || !existingFiles.isEmpty());
1242                    message.setAllowPingbacks(allowPingbacks);
1243    
1244                    if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
1245                            message.setPriority(priority);
1246                    }
1247    
1248                    // Attachments
1249    
1250                    long companyId = message.getCompanyId();
1251                    String portletId = CompanyConstants.SYSTEM_STRING;
1252                    long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1253                    long repositoryId = CompanyConstants.SYSTEM;
1254                    String dirName = message.getAttachmentsDir();
1255    
1256                    if (!files.isEmpty() || !existingFiles.isEmpty()) {
1257                            try {
1258                                    dlService.addDirectory(companyId, repositoryId, dirName);
1259                            }
1260                            catch (DuplicateDirectoryException dde) {
1261                            }
1262    
1263                            String[] fileNames = dlService.getFileNames(
1264                                    companyId, repositoryId, dirName);
1265    
1266                            for (String fileName: fileNames) {
1267                                    if (!existingFiles.contains(fileName)) {
1268                                            dlService.deleteFile(
1269                                                    companyId, portletId, repositoryId, fileName);
1270                                    }
1271                            }
1272    
1273                            for (int i = 0; i < files.size(); i++) {
1274                                    ObjectValuePair<String, byte[]> ovp = files.get(i);
1275    
1276                                    String fileName = ovp.getKey();
1277                                    byte[] bytes = ovp.getValue();
1278    
1279                                    try {
1280                                            dlService.addFile(
1281                                                    companyId, portletId, groupId, repositoryId,
1282                                                    dirName + "/" + fileName, 0, StringPool.BLANK,
1283                                                    message.getModifiedDate(), new ServiceContext(), bytes);
1284                                    }
1285                                    catch (DuplicateFileException dfe) {
1286                                    }
1287                            }
1288                    }
1289                    else {
1290                            try {
1291                                    dlService.deleteDirectory(
1292                                            companyId, portletId, repositoryId, dirName);
1293                            }
1294                            catch (NoSuchDirectoryException nsde) {
1295                            }
1296                    }
1297    
1298                    mbMessagePersistence.update(message, false);
1299    
1300                    // Thread
1301    
1302                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1303                            message.getThreadId());
1304    
1305                    if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) &&
1306                            (thread.getPriority() != priority)) {
1307    
1308                            thread.setPriority(priority);
1309    
1310                            mbThreadPersistence.update(thread, false);
1311    
1312                            updatePriorities(thread.getThreadId(), priority);
1313                    }
1314    
1315                    // Asset
1316    
1317                    updateAsset(
1318                            userId, message, serviceContext.getAssetCategoryIds(),
1319                            serviceContext.getAssetTagNames());
1320    
1321                    // Expando
1322    
1323                    ExpandoBridge expandoBridge = message.getExpandoBridge();
1324    
1325                    expandoBridge.setAttributes(serviceContext);
1326    
1327                    // Workflow
1328    
1329                    serviceContext.setAttribute("update", Boolean.TRUE.toString());
1330    
1331                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
1332                            companyId, message.getGroupId(), userId,
1333                            message.getWorkflowClassName(), message.getMessageId(), message,
1334                            serviceContext);
1335    
1336                    return message;
1337            }
1338    
1339            public MBMessage updateMessage(long messageId, String body)
1340                    throws PortalException, SystemException {
1341    
1342                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1343    
1344                    message.setBody(body);
1345    
1346                    mbMessagePersistence.update(message, false);
1347    
1348                    return message;
1349            }
1350    
1351            public MBMessage updateStatus(
1352                            long userId, long messageId, int status,
1353                            ServiceContext serviceContext)
1354                    throws PortalException, SystemException {
1355    
1356                    MBMessage message = getMessage(messageId);
1357    
1358                    int oldStatus = message.getStatus();
1359    
1360                    User user = userPersistence.findByPrimaryKey(userId);
1361                    Date now = new Date();
1362    
1363                    message.setStatus(status);
1364                    message.setStatusByUserId(userId);
1365                    message.setStatusByUserName(user.getFullName());
1366                    message.setStatusDate(serviceContext.getModifiedDate(now));
1367    
1368                    mbMessagePersistence.update(message, false);
1369    
1370                    // Thread
1371    
1372                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1373                            message.getThreadId());
1374    
1375                    MBCategory category = null;
1376    
1377                    if (!MBUtil.isDefaultParentCategoryId(thread.getCategoryId()) &&
1378                            !MBUtil.isDiscussionCategoryId(thread.getCategoryId())) {
1379    
1380                            category = mbCategoryPersistence.findByPrimaryKey(
1381                                    thread.getCategoryId());
1382                    }
1383    
1384                    if ((thread.getRootMessageId() == message.getMessageId()) &&
1385                            (oldStatus != status)) {
1386    
1387                            thread.setStatus(status);
1388                            thread.setStatusByUserId(userId);
1389                            thread.setStatusByUserName(user.getFullName());
1390                            thread.setStatusDate(serviceContext.getModifiedDate(now));
1391                    }
1392    
1393                    Indexer indexer = IndexerRegistryUtil.getIndexer(MBMessage.class);
1394    
1395                    if (status == WorkflowConstants.STATUS_APPROVED) {
1396                            if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
1397    
1398                                    // Thread
1399    
1400                                    if ((category != null) &&
1401                                            (thread.getRootMessageId() == message.getMessageId())) {
1402    
1403                                            category.setThreadCount(category.getThreadCount() + 1);
1404    
1405                                            mbCategoryPersistence.update(category, false);
1406                                    }
1407    
1408                                    thread.setMessageCount(thread.getMessageCount() + 1);
1409    
1410                                    if (message.isAnonymous()) {
1411                                            thread.setLastPostByUserId(0);
1412                                    }
1413                                    else {
1414                                            thread.setLastPostByUserId(message.getUserId());
1415                                    }
1416    
1417                                    thread.setLastPostDate(serviceContext.getModifiedDate(now));
1418    
1419                                    // Category
1420    
1421                                    if (category != null) {
1422                                            category.setMessageCount(category.getMessageCount() + 1);
1423                                            category.setLastPostDate(
1424                                                    serviceContext.getModifiedDate(now));
1425    
1426                                            mbCategoryPersistence.update(category, false);
1427    
1428                                    }
1429    
1430                                    // Asset
1431    
1432                                    if ((message.getClassNameId() == 0) ||
1433                                            (message.getParentMessageId() != 0)) {
1434    
1435                                            assetEntryLocalService.updateVisible(
1436                                                    message.getWorkflowClassName(), message.getMessageId(),
1437                                                    true);
1438                                    }
1439    
1440                                    if (!message.isDiscussion()) {
1441    
1442                                            // Social
1443    
1444                                            if (!message.isAnonymous() && !user.isDefaultUser()) {
1445                                                    int activityType = MBActivityKeys.ADD_MESSAGE;
1446                                                    long receiverUserId = 0;
1447                                                    String actionId = ActionKeys.ADD_MESSAGE;
1448    
1449                                                    MBMessage parentMessage =
1450                                                            mbMessagePersistence.fetchByPrimaryKey(
1451                                                                    message.getParentMessageId());
1452    
1453                                                    if (parentMessage != null) {
1454                                                            activityType = MBActivityKeys.REPLY_MESSAGE;
1455                                                            receiverUserId = parentMessage.getUserId();
1456    
1457                                                            if (receiverUserId != userId) {
1458                                                                    actionId = ActionKeys.REPLY_TO_MESSAGE;
1459                                                            }
1460                                                    }
1461    
1462                                                    socialActivityLocalService.addActivity(
1463                                                            userId, message.getGroupId(),
1464                                                            MBMessage.class.getName(), message.getMessageId(),
1465                                                            activityType, StringPool.BLANK, receiverUserId);
1466    
1467                                                    socialEquityLogLocalService.addEquityLogs(
1468                                                            userId, MBMessage.class.getName(), messageId,
1469                                                            actionId);
1470                                            }
1471                                    }
1472                                    else {
1473                                            String className = (String)serviceContext.getAttribute(
1474                                                    "className");
1475                                            long classPK = GetterUtil.getLong(
1476                                                    (String)serviceContext.getAttribute("classPK"));
1477    
1478                                            // Social
1479    
1480                                            if (!message.isRoot()) {
1481                                                    socialEquityLogLocalService.addEquityLogs(
1482                                                            userId, className, classPK,
1483                                                            ActionKeys.ADD_DISCUSSION);
1484                                            }
1485    
1486                                            long parentMessageId = message.getParentMessageId();
1487    
1488                                            if (className.equals(BlogsEntry.class.getName()) &&
1489                                                    (parentMessageId !=
1490                                                            MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID)) {
1491    
1492                                                    // Social
1493    
1494                                                    BlogsEntry entry =
1495                                                            blogsEntryPersistence.findByPrimaryKey(classPK);
1496    
1497                                                    JSONObject extraData =
1498                                                            JSONFactoryUtil.createJSONObject();
1499    
1500                                                    extraData.put("messageId", message.getMessageId());
1501    
1502                                                    socialActivityLocalService.addActivity(
1503                                                            userId, entry.getGroupId(),
1504                                                            BlogsEntry.class.getName(), classPK,
1505                                                            BlogsActivityKeys.ADD_COMMENT, extraData.toString(),
1506                                                            entry.getUserId());
1507    
1508                                                    // Email
1509    
1510                                                    try {
1511                                                            sendBlogsCommentsEmail(
1512                                                                    userId, entry, message, serviceContext);
1513                                                    }
1514                                                    catch (Exception e) {
1515                                                            _log.error(e, e);
1516                                                    }
1517                                            }
1518                                    }
1519    
1520                                    // Subscriptions
1521    
1522                                    notifySubscribers(message, serviceContext);
1523                            }
1524    
1525                            // Indexer
1526    
1527                            if (!message.isDiscussion()) {
1528                                    indexer.reindex(message);
1529                            }
1530    
1531                            // Ping
1532    
1533                            pingPingback(message, serviceContext);
1534                    }
1535                    else if ((oldStatus == WorkflowConstants.STATUS_APPROVED) &&
1536                                     (status != WorkflowConstants.STATUS_APPROVED)) {
1537    
1538                            // Thread
1539    
1540                            if ((category != null) &&
1541                                    (thread.getRootMessageId() == message.getMessageId())) {
1542    
1543                                    category.setThreadCount(category.getThreadCount() - 1);
1544    
1545                                    mbCategoryPersistence.update(category, false);
1546                            }
1547    
1548                            thread.setMessageCount(thread.getMessageCount() - 1);
1549    
1550                            // Category
1551    
1552                            if (category != null) {
1553                                    category.setMessageCount(category.getMessageCount() - 1);
1554    
1555                                    mbCategoryPersistence.update(category, false);
1556                            }
1557    
1558                            // Asset
1559    
1560                            assetEntryLocalService.updateVisible(
1561                                    message.getWorkflowClassName(), message.getMessageId(), false);
1562    
1563                            if (!message.isDiscussion()) {
1564    
1565                                    // Indexer
1566    
1567                                    indexer.delete(message);
1568                            }
1569                    }
1570    
1571                    if (status != oldStatus) {
1572                            mbThreadPersistence.update(thread, false);
1573                    }
1574    
1575                    // Statistics
1576    
1577                    if (!message.isDiscussion()) {
1578                            mbStatsUserLocalService.updateStatsUser(
1579                                    message.getGroupId(), userId,
1580                                    serviceContext.getModifiedDate(now));
1581                    }
1582    
1583                    return message;
1584            }
1585    
1586            public void updateUserName(long userId, String userName)
1587                    throws SystemException {
1588    
1589                    List<MBMessage> messages = mbMessagePersistence.findByUserId(userId);
1590    
1591                    for (MBMessage message : messages) {
1592                            message.setUserName(userName);
1593    
1594                            mbMessagePersistence.update(message, false);
1595                    }
1596            }
1597    
1598            protected void deleteDiscussionSocialActivities(
1599                            String className, List<MBMessage> messages)
1600                    throws PortalException, SystemException {
1601    
1602                    if (messages.size() == 0) {
1603                            return;
1604                    }
1605    
1606                    MBMessage message = messages.get(0);
1607    
1608                    MBDiscussion discussion = mbDiscussionPersistence.findByThreadId(
1609                            message.getThreadId());
1610    
1611                    long classNameId = PortalUtil.getClassNameId(className);
1612                    long classPK = discussion.getClassPK();
1613    
1614                    if (discussion.getClassNameId() != classNameId) {
1615                            return;
1616                    }
1617    
1618                    Set<Long> messageIds = new HashSet<Long>();
1619    
1620                    for (MBMessage curMessage : messages) {
1621                            messageIds.add(curMessage.getMessageId());
1622                    }
1623    
1624                    List<SocialActivity> socialActivities =
1625                            socialActivityLocalService.getActivities(
1626                                    0, className, classPK, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
1627    
1628                    for (SocialActivity socialActivity : socialActivities) {
1629                            if (Validator.isNull(socialActivity.getExtraData())) {
1630                                    continue;
1631                            }
1632    
1633                            JSONObject extraData = JSONFactoryUtil.createJSONObject(
1634                                    socialActivity.getExtraData());
1635    
1636                            long extraDataMessageId = extraData.getLong("messageId");
1637    
1638                            if (messageIds.contains(extraDataMessageId)) {
1639                                    socialActivityLocalService.deleteActivity(
1640                                            socialActivity.getActivityId());
1641                            }
1642                    }
1643            }
1644    
1645            protected void notifySubscribers(
1646                            MBMessage message, ServiceContext serviceContext)
1647                    throws PortalException, SystemException {
1648    
1649                    if (message.getStatus() != WorkflowConstants.STATUS_APPROVED) {
1650                            return;
1651                    }
1652    
1653                    String layoutFullURL = serviceContext.getLayoutFullURL();
1654    
1655                    if (Validator.isNull(layoutFullURL) || message.isDiscussion()) {
1656                            return;
1657                    }
1658    
1659                    PortletPreferences preferences =
1660                            ServiceContextUtil.getPortletPreferences(serviceContext);
1661    
1662                    if (preferences == null) {
1663                            long ownerId = message.getGroupId();
1664                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1665                            long plid = PortletKeys.PREFS_PLID_SHARED;
1666                            String portletId = PortletKeys.MESSAGE_BOARDS;
1667                            String defaultPreferences = null;
1668    
1669                            preferences = portletPreferencesLocalService.getPreferences(
1670                                    message.getCompanyId(), ownerId, ownerType, plid, portletId,
1671                                    defaultPreferences);
1672                    }
1673    
1674                    boolean update = GetterUtil.getBoolean(
1675                            (String)serviceContext.getAttribute("update"));
1676    
1677                    if (!update && MBUtil.getEmailMessageAddedEnabled(preferences)) {
1678                    }
1679                    else if (update && MBUtil.getEmailMessageUpdatedEnabled(preferences)) {
1680                    }
1681                    else {
1682                            return;
1683                    }
1684    
1685                    Company company = companyPersistence.findByPrimaryKey(
1686                            message.getCompanyId());
1687    
1688                    Group group = groupPersistence.findByPrimaryKey(message.getGroupId());
1689    
1690                    String emailAddress = StringPool.BLANK;
1691                    String fullName = message.getUserName();
1692    
1693                    try {
1694                            User user = userPersistence.findByPrimaryKey(message.getUserId());
1695    
1696                            emailAddress = user.getEmailAddress();
1697                            fullName = user.getFullName();
1698                    }
1699                    catch (NoSuchUserException nsue) {
1700                    }
1701    
1702                    MBCategory category = message.getCategory();
1703    
1704                    if (message.isAnonymous()) {
1705                            emailAddress = StringPool.BLANK;
1706                            fullName = LanguageUtil.get(
1707                                    ServiceContextUtil.getLocale(serviceContext), "anonymous");
1708                    }
1709    
1710                    String categoryName = category.getName();
1711    
1712                    if (category.getCategoryId() ==
1713                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
1714    
1715                            categoryName = LanguageUtil.get(
1716                                    ServiceContextUtil.getLocale(serviceContext),
1717                                    "message-boards-home") + StringPool.SPACE + StringPool.DASH +
1718                                    StringPool.SPACE + group.getName();
1719                    }
1720    
1721                    List<Long> categoryIds = new ArrayList<Long>();
1722    
1723                    categoryIds.add(message.getCategoryId());
1724    
1725                    if (!MBUtil.isDefaultParentCategoryId(message.getCategoryId()) &&
1726                            !MBUtil.isDiscussionCategoryId(message.getCategoryId())) {
1727    
1728                            categoryIds.addAll(category.getAncestorCategoryIds());
1729                    }
1730    
1731                    String messageURL =
1732                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR +
1733                                    "message_boards/view_message/" + message.getMessageId();
1734    
1735                    String portletName = PortalUtil.getPortletTitle(
1736                            PortletKeys.MESSAGE_BOARDS, LocaleUtil.getDefault());
1737    
1738                    String fromName = MBUtil.getEmailFromName(preferences);
1739                    String fromAddress = MBUtil.getEmailFromAddress(preferences);
1740    
1741                    String mailingListAddress = StringPool.BLANK;
1742    
1743                    if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
1744                            mailingListAddress = MBUtil.getMailingListAddress(
1745                                    message.getGroupId(), message.getCategoryId(),
1746                                    message.getMessageId(), company.getMx(), fromAddress);
1747                    }
1748    
1749                    String replyToAddress = mailingListAddress;
1750                    String mailId = MBUtil.getMailId(
1751                            company.getMx(), message.getCategoryId(), message.getMessageId());
1752    
1753                    fromName = StringUtil.replace(
1754                            fromName,
1755                            new String[] {
1756                                    "[$COMPANY_ID$]",
1757                                    "[$COMPANY_MX$]",
1758                                    "[$COMPANY_NAME$]",
1759                                    "[$COMMUNITY_NAME$]",
1760                                    "[$MAILING_LIST_ADDRESS$]",
1761                                    "[$MESSAGE_USER_ADDRESS$]",
1762                                    "[$MESSAGE_USER_NAME$]",
1763                                    "[$PORTLET_NAME$]"
1764                            },
1765                            new String[] {
1766                                    String.valueOf(company.getCompanyId()),
1767                                    company.getMx(),
1768                                    company.getName(),
1769                                    group.getName(),
1770                                    mailingListAddress,
1771                                    emailAddress,
1772                                    fullName,
1773                                    portletName
1774                            });
1775    
1776                    fromAddress = StringUtil.replace(
1777                            fromAddress,
1778                            new String[] {
1779                                    "[$COMPANY_ID$]",
1780                                    "[$COMPANY_MX$]",
1781                                    "[$COMPANY_NAME$]",
1782                                    "[$COMMUNITY_NAME$]",
1783                                    "[$MAILING_LIST_ADDRESS$]",
1784                                    "[$MESSAGE_USER_ADDRESS$]",
1785                                    "[$MESSAGE_USER_NAME$]",
1786                                    "[$PORTLET_NAME$]"
1787                            },
1788                            new String[] {
1789                                    String.valueOf(company.getCompanyId()),
1790                                    company.getMx(),
1791                                    company.getName(),
1792                                    group.getName(),
1793                                    mailingListAddress,
1794                                    emailAddress,
1795                                    fullName,
1796                                    portletName
1797                            });
1798    
1799                    String subjectPrefix = null;
1800                    String body = null;
1801                    String signature = null;
1802                    boolean htmlFormat = MBUtil.getEmailHtmlFormat(preferences);
1803    
1804                    if (update) {
1805                            subjectPrefix = MBUtil.getEmailMessageUpdatedSubjectPrefix(
1806                                    preferences);
1807                            body = MBUtil.getEmailMessageUpdatedBody(preferences);
1808                            signature = MBUtil.getEmailMessageUpdatedSignature(preferences);
1809                    }
1810                    else {
1811                            subjectPrefix = MBUtil.getEmailMessageAddedSubjectPrefix(
1812                                    preferences);
1813                            body = MBUtil.getEmailMessageAddedBody(preferences);
1814                            signature = MBUtil.getEmailMessageAddedSignature(preferences);
1815                    }
1816    
1817                    if (Validator.isNotNull(signature)) {
1818                            body +=  "\n--\n" + signature;
1819                    }
1820    
1821                    subjectPrefix = StringUtil.replace(
1822                            subjectPrefix,
1823                            new String[] {
1824                                    "[$CATEGORY_NAME$]",
1825                                    "[$COMPANY_ID$]",
1826                                    "[$COMPANY_MX$]",
1827                                    "[$COMPANY_NAME$]",
1828                                    "[$COMMUNITY_NAME$]",
1829                                    "[$FROM_ADDRESS$]",
1830                                    "[$FROM_NAME$]",
1831                                    "[$MAILING_LIST_ADDRESS$]",
1832                                    "[$MESSAGE_BODY$]",
1833                                    "[$MESSAGE_ID$]",
1834                                    "[$MESSAGE_SUBJECT$]",
1835                                    "[$MESSAGE_USER_ADDRESS$]",
1836                                    "[$MESSAGE_USER_NAME$]",
1837                                    "[$PORTAL_URL$]",
1838                                    "[$PORTLET_NAME$]"
1839                            },
1840                            new String[] {
1841                                    categoryName,
1842                                    String.valueOf(company.getCompanyId()),
1843                                    company.getMx(),
1844                                    company.getName(),
1845                                    group.getName(),
1846                                    fromAddress,
1847                                    fromName,
1848                                    mailingListAddress,
1849                                    message.getBody(),
1850                                    String.valueOf(message.getMessageId()),
1851                                    message.getSubject(),
1852                                    emailAddress,
1853                                    fullName,
1854                                    company.getVirtualHost(),
1855                                    portletName
1856                            });
1857    
1858                    body = StringUtil.replace(
1859                            body,
1860                            new String[] {
1861                                    "[$CATEGORY_NAME$]",
1862                                    "[$COMPANY_ID$]",
1863                                    "[$COMPANY_MX$]",
1864                                    "[$COMPANY_NAME$]",
1865                                    "[$COMMUNITY_NAME$]",
1866                                    "[$FROM_ADDRESS$]",
1867                                    "[$FROM_NAME$]",
1868                                    "[$MAILING_LIST_ADDRESS$]",
1869                                    "[$MESSAGE_BODY$]",
1870                                    "[$MESSAGE_ID$]",
1871                                    "[$MESSAGE_SUBJECT$]",
1872                                    "[$MESSAGE_URL$]",
1873                                    "[$MESSAGE_USER_ADDRESS$]",
1874                                    "[$MESSAGE_USER_NAME$]",
1875                                    "[$PORTAL_URL$]",
1876                                    "[$PORTLET_NAME$]"
1877                            },
1878                            new String[] {
1879                                    categoryName,
1880                                    String.valueOf(company.getCompanyId()),
1881                                    company.getMx(),
1882                                    company.getName(),
1883                                    group.getName(),
1884                                    fromAddress,
1885                                    fromName,
1886                                    mailingListAddress,
1887                                    message.getBody(),
1888                                    String.valueOf(message.getMessageId()),
1889                                    message.getSubject(),
1890                                    messageURL,
1891                                    emailAddress,
1892                                    fullName,
1893                                    company.getVirtualHost(),
1894                                    portletName
1895                            });
1896    
1897                    String subject = message.getSubject();
1898    
1899                    if (subject.indexOf(subjectPrefix) == -1) {
1900                            subject = subjectPrefix.trim() + " " + subject.trim();
1901                    }
1902    
1903                    String inReplyTo = null;
1904    
1905                    if (message.getParentMessageId() !=
1906                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
1907    
1908                            inReplyTo = MBUtil.getMailId(
1909                                    company.getMx(), message.getCategoryId(),
1910                                    message.getParentMessageId());
1911                    }
1912    
1913                    com.liferay.portal.kernel.messaging.Message messagingObj =
1914                            new com.liferay.portal.kernel.messaging.Message();
1915    
1916                    messagingObj.put("companyId", message.getCompanyId());
1917                    messagingObj.put("userId", message.getUserId());
1918                    messagingObj.put("groupId", message.getGroupId());
1919                    messagingObj.put("categoryIds", StringUtil.merge(categoryIds));
1920                    messagingObj.put("threadId", message.getThreadId());
1921                    messagingObj.put("fromName", fromName);
1922                    messagingObj.put("fromAddress", fromAddress);
1923                    messagingObj.put("subject", subject);
1924                    messagingObj.put("body", body);
1925                    messagingObj.put("replyToAddress", replyToAddress);
1926                    messagingObj.put("mailId", mailId);
1927                    messagingObj.put("inReplyTo", inReplyTo);
1928                    messagingObj.put("htmlFormat", htmlFormat);
1929                    messagingObj.put(
1930                            "sourceMailingList", MailingListThreadLocal.isSourceMailingList());
1931    
1932                    MessageBusUtil.sendMessage(
1933                            DestinationNames.MESSAGE_BOARDS, messagingObj);
1934            }
1935    
1936            protected void pingPingback(
1937                    MBMessage message, ServiceContext serviceContext) {
1938    
1939                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
1940                            !message.isAllowPingbacks() ||
1941                            (message.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
1942    
1943                            return;
1944                    }
1945    
1946                    String layoutFullURL = serviceContext.getLayoutFullURL();
1947    
1948                    if (Validator.isNull(layoutFullURL)) {
1949                            return;
1950                    }
1951    
1952                    String sourceUri =
1953                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR +
1954                                    "message_boards/view_message/" + message.getMessageId();
1955    
1956                    Source source = new Source(message.getBody(true));
1957    
1958                    List<StartTag> startTags = source.getAllStartTags("a");
1959    
1960                    for (StartTag startTag : startTags) {
1961                            String targetUri = startTag.getAttributeValue("href");
1962    
1963                            if (Validator.isNotNull(targetUri)) {
1964                                    try {
1965                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
1966                                    }
1967                                    catch (Exception e) {
1968                                            _log.error("Error while sending pingback " + targetUri, e);
1969                                    }
1970                            }
1971                    }
1972            }
1973    
1974            protected void sendBlogsCommentsEmail(
1975                            long userId, BlogsEntry entry, MBMessage message,
1976                            ServiceContext serviceContext)
1977                    throws IOException, PortalException, SystemException {
1978    
1979                    long companyId = message.getCompanyId();
1980    
1981                    if (!PrefsPropsUtil.getBoolean(
1982                                    companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_ENABLED)) {
1983    
1984                            return;
1985                    }
1986    
1987                    String layoutFullURL = serviceContext.getLayoutFullURL();
1988    
1989                    String blogsEntryURL =
1990                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1991                                    entry.getUrlTitle();
1992    
1993                    User user = userPersistence.findByPrimaryKey(userId);
1994    
1995                    String fromName = PrefsPropsUtil.getString(
1996                            companyId, PropsKeys.ADMIN_EMAIL_FROM_NAME);
1997                    String fromAddress = PrefsPropsUtil.getString(
1998                            companyId, PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);
1999    
2000                    String subject = PrefsPropsUtil.getContent(
2001                            companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_SUBJECT);
2002                    String body = PrefsPropsUtil.getContent(
2003                            companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_BODY);
2004    
2005                    subject = StringUtil.replace(
2006                            subject,
2007                            new String[] {
2008                                    "[$BLOGS_COMMENTS_BODY$]",
2009                                    "[$BLOGS_COMMENTS_USER_ADDRESS$]",
2010                                    "[$BLOGS_COMMENTS_USER_NAME$]",
2011                                    "[$BLOGS_ENTRY_URL$]",
2012                                    "[$FROM_ADDRESS$]",
2013                                    "[$FROM_NAME$]"
2014                            },
2015                            new String[] {
2016                                    message.getBody(),
2017                                    user.getEmailAddress(),
2018                                    user.getFullName(),
2019                                    blogsEntryURL,
2020                                    fromAddress,
2021                                    fromName
2022                            });
2023    
2024                    body = StringUtil.replace(
2025                            body,
2026                            new String[] {
2027                                    "[$BLOGS_COMMENTS_BODY$]",
2028                                    "[$BLOGS_COMMENTS_USER_ADDRESS$]",
2029                                    "[$BLOGS_COMMENTS_USER_NAME$]",
2030                                    "[$BLOGS_ENTRY_URL$]",
2031                                    "[$FROM_ADDRESS$]",
2032                                    "[$FROM_NAME$]"
2033                            },
2034                            new String[] {
2035                                    message.getBody(),
2036                                    user.getEmailAddress(),
2037                                    user.getFullName(),
2038                                    blogsEntryURL,
2039                                    fromAddress,
2040                                    fromName
2041                            });
2042    
2043                    Set<Long> sent = new HashSet<Long>();
2044    
2045                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
2046                            message.getThreadId());
2047    
2048                    for (MBMessage curMessage : messages) {
2049                            long curMessageUserId = curMessage.getUserId();
2050    
2051                            if (curMessageUserId == userId) {
2052                                    continue;
2053                            }
2054    
2055                            if (sent.contains(curMessageUserId)) {
2056                                    if (_log.isDebugEnabled()) {
2057                                            _log.debug(
2058                                                    "Do not send a duplicate email to user " +
2059                                                            curMessageUserId);
2060                                    }
2061    
2062                                    continue;
2063                            }
2064                            else {
2065                                    if (_log.isDebugEnabled()) {
2066                                            _log.debug(
2067                                                    "Add user " + curMessageUserId +
2068                                                            " to the list of users who have received an email");
2069                                    }
2070    
2071                                    sent.add(curMessageUserId);
2072                            }
2073    
2074                            User curMessageUser = null;
2075    
2076                            try {
2077                                    curMessageUser = userLocalService.getUserById(curMessageUserId);
2078                            }
2079                            catch (NoSuchUserException nsue) {
2080                                    continue;
2081                            }
2082    
2083                            if (!curMessageUser.isActive()) {
2084                                    continue;
2085                            }
2086    
2087                            InternetAddress from = new InternetAddress(fromAddress, fromName);
2088    
2089                            InternetAddress to = new InternetAddress(
2090                                    curMessageUser.getEmailAddress(), curMessageUser.getFullName());
2091    
2092                            String curSubject = StringUtil.replace(
2093                                    subject,
2094                                    new String[] {
2095                                            "[$TO_ADDRESS$]",
2096                                            "[$TO_NAME$]"
2097                                    },
2098                                    new String[] {
2099                                            curMessageUser.getFullName(),
2100                                            curMessageUser.getEmailAddress()
2101                                    });
2102    
2103                            String curBody = StringUtil.replace(
2104                                    body,
2105                                    new String[] {
2106                                            "[$TO_ADDRESS$]",
2107                                            "[$TO_NAME$]"
2108                                    },
2109                                    new String[] {
2110                                            curMessageUser.getFullName(),
2111                                            curMessageUser.getEmailAddress()
2112                                    });
2113    
2114                            MailMessage mailMessage = new MailMessage(
2115                                    from, to, curSubject, curBody, true);
2116    
2117                            mailService.sendEmail(mailMessage);
2118                    }
2119            }
2120    
2121            protected void updatePriorities(long threadId, double priority)
2122                    throws SystemException {
2123    
2124                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
2125                            threadId);
2126    
2127                    for (MBMessage message : messages) {
2128                            if (message.getPriority() != priority) {
2129                                    message.setPriority(priority);
2130    
2131                                    mbMessagePersistence.update(message, false);
2132                            }
2133                    }
2134            }
2135    
2136            protected void validate(String subject, String body)
2137                    throws PortalException {
2138    
2139                    if (Validator.isNull(subject)) {
2140                            throw new MessageSubjectException();
2141                    }
2142    
2143                    if (Validator.isNull(body)) {
2144                            throw new MessageBodyException();
2145                    }
2146            }
2147    
2148            private static Log _log = LogFactoryUtil.getLog(
2149                    MBMessageLocalServiceImpl.class);
2150    
2151    }