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