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