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