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