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