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