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