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