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