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