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