1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   * 
13   */
14  
15  package com.liferay.portlet.messageboards.service.impl;
16  
17  import com.liferay.documentlibrary.DuplicateDirectoryException;
18  import com.liferay.documentlibrary.DuplicateFileException;
19  import com.liferay.documentlibrary.NoSuchDirectoryException;
20  import com.liferay.portal.NoSuchUserException;
21  import com.liferay.portal.PortalException;
22  import com.liferay.portal.SystemException;
23  import com.liferay.portal.kernel.dao.orm.QueryUtil;
24  import com.liferay.portal.kernel.json.JSONFactoryUtil;
25  import com.liferay.portal.kernel.json.JSONObject;
26  import com.liferay.portal.kernel.language.LanguageUtil;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.mail.MailMessage;
30  import com.liferay.portal.kernel.messaging.DestinationNames;
31  import com.liferay.portal.kernel.messaging.MessageBusUtil;
32  import com.liferay.portal.kernel.search.SearchEngineUtil;
33  import com.liferay.portal.kernel.search.SearchException;
34  import com.liferay.portal.kernel.util.ContentTypes;
35  import com.liferay.portal.kernel.util.ListUtil;
36  import com.liferay.portal.kernel.util.LocaleUtil;
37  import com.liferay.portal.kernel.util.ObjectValuePair;
38  import com.liferay.portal.kernel.util.OrderByComparator;
39  import com.liferay.portal.kernel.util.PropsKeys;
40  import com.liferay.portal.kernel.util.StringPool;
41  import com.liferay.portal.kernel.util.StringUtil;
42  import com.liferay.portal.kernel.util.Validator;
43  import com.liferay.portal.model.Company;
44  import com.liferay.portal.model.CompanyConstants;
45  import com.liferay.portal.model.Group;
46  import com.liferay.portal.model.GroupConstants;
47  import com.liferay.portal.model.ModelHintsUtil;
48  import com.liferay.portal.model.ResourceConstants;
49  import com.liferay.portal.model.User;
50  import com.liferay.portal.security.auth.PrincipalException;
51  import com.liferay.portal.service.ServiceContext;
52  import com.liferay.portal.service.ServiceContextUtil;
53  import com.liferay.portal.util.Portal;
54  import com.liferay.portal.util.PortalUtil;
55  import com.liferay.portal.util.PortletKeys;
56  import com.liferay.portal.util.PrefsPropsUtil;
57  import com.liferay.portal.util.PropsValues;
58  import com.liferay.portlet.blogs.model.BlogsEntry;
59  import com.liferay.portlet.blogs.social.BlogsActivityKeys;
60  import com.liferay.portlet.expando.model.ExpandoBridge;
61  import com.liferay.portlet.messageboards.MessageBodyException;
62  import com.liferay.portlet.messageboards.MessageSubjectException;
63  import com.liferay.portlet.messageboards.NoSuchDiscussionException;
64  import com.liferay.portlet.messageboards.RequiredMessageException;
65  import com.liferay.portlet.messageboards.model.MBCategory;
66  import com.liferay.portlet.messageboards.model.MBDiscussion;
67  import com.liferay.portlet.messageboards.model.MBMessage;
68  import com.liferay.portlet.messageboards.model.MBMessageDisplay;
69  import com.liferay.portlet.messageboards.model.MBThread;
70  import com.liferay.portlet.messageboards.model.impl.MBMessageDisplayImpl;
71  import com.liferay.portlet.messageboards.model.impl.MBMessageImpl;
72  import com.liferay.portlet.messageboards.model.impl.MBThreadImpl;
73  import com.liferay.portlet.messageboards.service.base.MBMessageLocalServiceBaseImpl;
74  import com.liferay.portlet.messageboards.social.MBActivityKeys;
75  import com.liferay.portlet.messageboards.util.Indexer;
76  import com.liferay.portlet.messageboards.util.MBUtil;
77  import com.liferay.portlet.messageboards.util.MailingListThreadLocal;
78  import com.liferay.portlet.messageboards.util.comparator.MessageThreadComparator;
79  import com.liferay.portlet.messageboards.util.comparator.ThreadLastPostDateComparator;
80  import com.liferay.portlet.social.model.SocialActivity;
81  
82  import java.io.IOException;
83  
84  import java.util.ArrayList;
85  import java.util.Comparator;
86  import java.util.Date;
87  import java.util.HashSet;
88  import java.util.Iterator;
89  import java.util.List;
90  import java.util.Set;
91  
92  import javax.mail.internet.InternetAddress;
93  
94  import javax.portlet.PortletPreferences;
95  
96  /**
97   * <a href="MBMessageLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
98   *
99   * @author Brian Wing Shun Chan
100  * @author Raymond Augé
101  */
102 public class MBMessageLocalServiceImpl extends MBMessageLocalServiceBaseImpl {
103 
104     public MBMessage addDiscussionMessage(
105             long userId, String userName, String className, long classPK)
106         throws PortalException, SystemException {
107 
108         long threadId = 0;
109         long parentMessageId = 0;
110         String subject = String.valueOf(classPK);
111         String body = subject;
112         ServiceContext serviceContext = new ServiceContext();
113 
114         return addDiscussionMessage(
115             userId, userName, className, classPK, threadId, parentMessageId,
116             subject, body, serviceContext);
117     }
118 
119     public MBMessage addDiscussionMessage(
120             long userId, String userName, String className, long classPK,
121             long threadId, long parentMessageId, String subject, String body,
122             ServiceContext serviceContext)
123         throws PortalException, SystemException {
124 
125         long classNameId = PortalUtil.getClassNameId(className);
126         long categoryId = CompanyConstants.SYSTEM;
127 
128         if (Validator.isNull(subject)) {
129             subject = "N/A";
130         }
131 
132         List<ObjectValuePair<String, byte[]>> files =
133             new ArrayList<ObjectValuePair<String, byte[]>>();
134         boolean anonymous = false;
135         double priority = 0.0;
136 
137         serviceContext.setAddCommunityPermissions(true);
138         serviceContext.setAddGuestPermissions(true);
139 
140         mbCategoryLocalService.getSystemCategory();
141 
142         MBMessage message = addMessage(
143             userId, userName, categoryId, threadId, parentMessageId, subject,
144             body, files, anonymous, priority, serviceContext);
145 
146         message.setClassNameId(classNameId);
147         message.setClassPK(classPK);
148 
149         mbMessagePersistence.update(message, false);
150 
151         if (className.equals(BlogsEntry.class.getName()) &&
152             parentMessageId != MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID) {
153 
154             // Social
155 
156             BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(classPK);
157 
158             JSONObject extraData = JSONFactoryUtil.createJSONObject();
159 
160             extraData.put("messageId", message.getMessageId());
161 
162             socialActivityLocalService.addActivity(
163                 userId, entry.getGroupId(), BlogsEntry.class.getName(),
164                 classPK, BlogsActivityKeys.ADD_COMMENT, extraData.toString(),
165                 entry.getUserId());
166 
167             // Email
168 
169             try {
170                 sendBlogsCommentsEmail(userId, entry, message, serviceContext);
171             }
172             catch (Exception e) {
173                 _log.error(e, e);
174             }
175         }
176 
177         if (parentMessageId == MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID) {
178             MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
179                 classNameId, classPK);
180 
181             if (discussion == null) {
182                 discussion = mbDiscussionLocalService.addDiscussion(
183                     classNameId, classPK, message.getThreadId());
184             }
185         }
186 
187         return message;
188     }
189 
190     public MBMessage addMessage(
191             long userId, String userName, long categoryId, long threadId,
192             long parentMessageId, String subject, String body,
193             List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
194             double priority, ServiceContext serviceContext)
195         throws PortalException, SystemException {
196 
197         return addMessage(
198             null, userId, userName, categoryId, threadId, parentMessageId,
199             subject, body, files, anonymous, priority, serviceContext);
200     }
201 
202     public MBMessage addMessage(
203             long userId, String userName, long categoryId, String subject,
204             String body, List<ObjectValuePair<String, byte[]>> files,
205             boolean anonymous, double priority, ServiceContext serviceContext)
206         throws PortalException, SystemException {
207 
208         long threadId = 0;
209         long parentMessageId = 0;
210 
211         return addMessage(
212             null, userId, userName, categoryId, threadId, parentMessageId,
213             subject, body, files, anonymous, priority, serviceContext);
214     }
215 
216     public MBMessage addMessage(
217             String uuid, long userId, String userName, long categoryId,
218             long threadId, long parentMessageId, String subject, String body,
219             List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
220             double priority, ServiceContext serviceContext)
221         throws PortalException, SystemException {
222 
223         // Message
224 
225         User user = userPersistence.findByPrimaryKey(userId);
226         userName = user.isDefaultUser() ? userName : user.getFullName();
227         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
228             categoryId);
229         subject = ModelHintsUtil.trimString(
230             MBMessage.class.getName(), "subject", subject);
231 
232         PortletPreferences preferences =
233             ServiceContextUtil.getPortletPreferences(serviceContext);
234 
235         if (preferences != null) {
236             if (!MBUtil.isAllowAnonymousPosting(preferences)) {
237                 if (anonymous || user.isDefaultUser()) {
238                     throw new PrincipalException();
239                 }
240             }
241         }
242 
243         if (user.isDefaultUser()) {
244             anonymous = true;
245         }
246 
247         Date now = new Date();
248 
249         validate(subject, body);
250 
251         long messageId = counterLocalService.increment();
252 
253         MBMessage message = mbMessagePersistence.create(messageId);
254 
255         message.setUuid(uuid);
256         message.setGroupId(category.getGroupId());
257         message.setCompanyId(user.getCompanyId());
258         message.setUserId(user.getUserId());
259         message.setUserName(userName);
260         message.setCreateDate(now);
261         message.setModifiedDate(now);
262 
263         // Thread
264 
265         MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(
266             parentMessageId);
267 
268         if (parentMessage == null) {
269             parentMessageId = MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID;
270         }
271 
272         MBThread thread = null;
273 
274         if (threadId > 0) {
275             thread = mbThreadPersistence.fetchByPrimaryKey(threadId);
276         }
277 
278         if ((thread == null) ||
279             (parentMessageId == MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID)) {
280 
281             threadId = counterLocalService.increment();
282 
283             thread = mbThreadPersistence.create(threadId);
284 
285             thread.setGroupId(category.getGroupId());
286             thread.setCategoryId(categoryId);
287             thread.setRootMessageId(messageId);
288             if (!category.isDiscussion()) {
289                 category.setThreadCount(category.getThreadCount() + 1);
290             }
291         }
292 
293         thread.setMessageCount(thread.getMessageCount() + 1);
294 
295         if (anonymous) {
296             thread.setLastPostByUserId(0);
297         }
298         else {
299             thread.setLastPostByUserId(userId);
300         }
301 
302         thread.setLastPostDate(now);
303 
304         if ((priority != MBThreadImpl.PRIORITY_NOT_GIVEN) &&
305             (thread.getPriority() != priority)) {
306 
307             thread.setPriority(priority);
308 
309             updatePriorities(thread.getThreadId(), priority);
310         }
311 
312         // Message
313 
314         message.setCategoryId(categoryId);
315         message.setThreadId(threadId);
316         message.setParentMessageId(parentMessageId);
317         message.setSubject(subject);
318         message.setBody(body);
319         message.setAttachments(!files.isEmpty());
320         message.setAnonymous(anonymous);
321 
322         if (priority != MBThreadImpl.PRIORITY_NOT_GIVEN) {
323             message.setPriority(priority);
324         }
325 
326         // Attachments
327 
328         if (files.size() > 0) {
329             long companyId = message.getCompanyId();
330             String portletId = CompanyConstants.SYSTEM_STRING;
331             long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
332             long repositoryId = CompanyConstants.SYSTEM;
333             String dirName = message.getAttachmentsDir();
334 
335             try {
336                 dlService.deleteDirectory(
337                     companyId, portletId, repositoryId, dirName);
338             }
339             catch (NoSuchDirectoryException nsde) {
340                 if (_log.isDebugEnabled()) {
341                     _log.debug(nsde.getMessage());
342                 }
343             }
344 
345             dlService.addDirectory(companyId, repositoryId, dirName);
346 
347             for (int i = 0; i < files.size(); i++) {
348                 ObjectValuePair<String, byte[]> ovp = files.get(i);
349 
350                 String fileName = ovp.getKey();
351                 byte[] bytes = ovp.getValue();
352 
353                 try {
354                     dlService.addFile(
355                         companyId, portletId, groupId, repositoryId,
356                         dirName + "/" + fileName, 0, StringPool.BLANK,
357                         message.getModifiedDate(), new String[0], new String[0],
358                         bytes);
359                 }
360                 catch (DuplicateFileException dfe) {
361                     if (_log.isDebugEnabled()) {
362                         _log.debug(dfe.getMessage());
363                     }
364                 }
365             }
366         }
367 
368         // Commit
369 
370         mbThreadPersistence.update(thread, false);
371         mbMessagePersistence.update(message, false);
372 
373         // Resources
374 
375         if (!category.isDiscussion()) {
376             if (user.isDefaultUser()) {
377                 addMessageResources(message, true, true);
378             }
379             if (serviceContext.getAddCommunityPermissions() ||
380                 serviceContext.getAddGuestPermissions()) {
381 
382                 addMessageResources(
383                     message, serviceContext.getAddCommunityPermissions(),
384                     serviceContext.getAddGuestPermissions());
385             }
386             else {
387                 addMessageResources(
388                     message, serviceContext.getCommunityPermissions(),
389                     serviceContext.getGuestPermissions());
390             }
391         }
392 
393         if (!message.isDiscussion()) {
394 
395             // Statistics
396 
397             mbStatsUserLocalService.updateStatsUser(
398                 message.getGroupId(), userId, now);
399 
400             // Category
401 
402             category.setMessageCount(category.getMessageCount() + 1);
403             category.setLastPostDate(now);
404 
405             mbCategoryPersistence.update(category, false);
406         }
407 
408         // Subscriptions
409 
410         notifySubscribers(category, message, serviceContext, false);
411 
412         // Social
413 
414         if (!message.isDiscussion() && !message.isAnonymous() &&
415             !user.isDefaultUser()) {
416 
417             int activityType = MBActivityKeys.ADD_MESSAGE;
418             long receiverUserId = 0;
419 
420             if (parentMessage != null) {
421                 activityType = MBActivityKeys.REPLY_MESSAGE;
422                 receiverUserId = parentMessage.getUserId();
423             }
424 
425             socialActivityLocalService.addActivity(
426                 userId, message.getGroupId(), MBMessage.class.getName(),
427                 messageId, activityType, StringPool.BLANK, receiverUserId);
428         }
429 
430         // Tags
431 
432         updateTagsAsset(userId, message, serviceContext.getTagsEntries());
433 
434         // Testing roll back
435 
436         /*if (true) {
437             throw new SystemException("Testing roll back");
438         }*/
439 
440         // Indexer
441 
442         reIndex(message);
443 
444         return message;
445     }
446 
447     public void addMessageResources(
448             long messageId, boolean addCommunityPermissions,
449             boolean addGuestPermissions)
450         throws PortalException, SystemException {
451 
452         MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
453 
454         addMessageResources(
455             message, addCommunityPermissions, addGuestPermissions);
456     }
457 
458     public void addMessageResources(
459             long messageId, String[] communityPermissions,
460             String[] guestPermissions)
461         throws PortalException, SystemException {
462 
463         MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
464 
465         addMessageResources(message, communityPermissions, guestPermissions);
466     }
467 
468     public void addMessageResources(
469             MBMessage message, boolean addCommunityPermissions,
470             boolean addGuestPermissions)
471         throws PortalException, SystemException {
472 
473         resourceLocalService.addResources(
474             message.getCompanyId(), message.getGroupId(), message.getUserId(),
475             MBMessage.class.getName(), message.getMessageId(),
476             false, addCommunityPermissions, addGuestPermissions);
477     }
478 
479     public void addMessageResources(
480             MBMessage message, String[] communityPermissions,
481             String[] guestPermissions)
482         throws PortalException, SystemException {
483 
484         resourceLocalService.addModelResources(
485             message.getCompanyId(), message.getGroupId(), message.getUserId(),
486             MBMessage.class.getName(), message.getMessageId(),
487             communityPermissions, guestPermissions);
488     }
489 
490     public void deleteDiscussionMessage(long messageId)
491         throws PortalException, SystemException {
492 
493         MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
494 
495         List<MBMessage> messages = new ArrayList<MBMessage>();
496 
497         messages.add(message);
498 
499         deleteDiscussionSocialActivities(BlogsEntry.class.getName(), messages);
500 
501         deleteMessage(message);
502     }
503 
504     public void deleteDiscussionMessages(String className, long classPK)
505         throws PortalException, SystemException {
506 
507         try {
508             long classNameId = PortalUtil.getClassNameId(className);
509 
510             MBDiscussion discussion = mbDiscussionPersistence.findByC_C(
511                 classNameId, classPK);
512 
513             List<MBMessage> messages = mbMessagePersistence.findByT_P(
514                 discussion.getThreadId(),
515                 MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID, 0, 1);
516 
517             deleteDiscussionSocialActivities(
518                 BlogsEntry.class.getName(), messages);
519 
520             if (messages.size() > 0) {
521                 MBMessage message = messages.get(0);
522 
523                 mbThreadLocalService.deleteThread(message.getThreadId());
524             }
525 
526             mbDiscussionPersistence.remove(discussion);
527         }
528         catch (NoSuchDiscussionException nsde) {
529             if (_log.isDebugEnabled()) {
530                 _log.debug(nsde.getMessage());
531             }
532         }
533     }
534 
535     public void deleteMessage(long messageId)
536         throws PortalException, SystemException {
537 
538         MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
539 
540         deleteMessage(message);
541     }
542 
543     public void deleteMessage(MBMessage message)
544         throws PortalException, SystemException {
545 
546         // Indexer
547 
548         try {
549             Indexer.deleteMessage(
550                 message.getCompanyId(), message.getMessageId());
551         }
552         catch (SearchException se) {
553             _log.error("Deleting index " + message.getMessageId(), se);
554         }
555 
556         // Attachments
557 
558         if (message.isAttachments()) {
559             long companyId = message.getCompanyId();
560             String portletId = CompanyConstants.SYSTEM_STRING;
561             long repositoryId = CompanyConstants.SYSTEM;
562             String dirName = message.getAttachmentsDir();
563 
564             try {
565                 dlService.deleteDirectory(
566                     companyId, portletId, repositoryId, dirName);
567             }
568             catch (NoSuchDirectoryException nsde) {
569                 if (_log.isDebugEnabled()) {
570                     _log.debug(nsde.getMessage());
571                 }
572             }
573         }
574 
575         // Thread
576 
577         int count = mbMessagePersistence.countByThreadId(message.getThreadId());
578 
579         // Message flags
580 
581         if (message.isRoot()) {
582             mbMessageFlagLocalService.deleteQuestionAndAnswerFlags(
583                 message.getThreadId());
584         }
585 
586         if (count == 1) {
587 
588             // Attachments
589 
590             long companyId = message.getCompanyId();
591             String portletId = CompanyConstants.SYSTEM_STRING;
592             long repositoryId = CompanyConstants.SYSTEM;
593             String dirName = message.getThreadAttachmentsDir();
594 
595             try {
596                 dlService.deleteDirectory(
597                     companyId, portletId, repositoryId, dirName);
598             }
599             catch (NoSuchDirectoryException nsde) {
600                 if (_log.isDebugEnabled()) {
601                     _log.debug(nsde.getMessage());
602                 }
603             }
604 
605             // Subscriptions
606 
607             subscriptionLocalService.deleteSubscriptions(
608                 message.getCompanyId(), MBThread.class.getName(),
609                 message.getThreadId());
610 
611             // Thread
612 
613             mbThreadPersistence.remove(message.getThreadId());
614 
615             // Category
616 
617             if (!message.isDiscussion()) {
618                 MBCategory category = mbCategoryPersistence.findByPrimaryKey(
619                     message.getCategoryId());
620 
621                 category.setThreadCount(category.getThreadCount() - 1);
622                 category.setMessageCount(category.getMessageCount() - 1);
623 
624                 mbCategoryPersistence.update(category, false);
625             }
626         }
627         else if (count > 1) {
628             MBThread thread = mbThreadPersistence.findByPrimaryKey(
629                 message.getThreadId());
630 
631             // Message is a root message
632 
633             if (thread.getRootMessageId() == message.getMessageId()) {
634                 List<MBMessage> childrenMessages =
635                     mbMessagePersistence.findByT_P(
636                         message.getThreadId(), message.getMessageId());
637 
638                 if (childrenMessages.size() > 1) {
639                     throw new RequiredMessageException(
640                         String.valueOf(message.getMessageId()));
641                 }
642                 else if (childrenMessages.size() == 1) {
643                     MBMessage childMessage = childrenMessages.get(0);
644 
645                     childMessage.setParentMessageId(
646                         MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID);
647 
648                     mbMessagePersistence.update(childMessage, false);
649 
650                     thread.setRootMessageId(childMessage.getMessageId());
651 
652                     mbThreadPersistence.update(thread, false);
653                 }
654             }
655 
656             // Message is a child message
657 
658             else {
659                 List<MBMessage> childrenMessages =
660                     mbMessagePersistence.findByT_P(
661                         message.getThreadId(), message.getMessageId());
662 
663                 // Message has children messages
664 
665                 if (childrenMessages.size() > 0) {
666                     Iterator<MBMessage> itr = childrenMessages.iterator();
667 
668                     while (itr.hasNext()) {
669                         MBMessage childMessage = itr.next();
670 
671                         childMessage.setParentMessageId(
672                             message.getParentMessageId());
673 
674                         mbMessagePersistence.update(childMessage, false);
675                     }
676                 }
677             }
678 
679             // Thread
680 
681             thread.setMessageCount(count - 1);
682 
683             mbThreadPersistence.update(thread, false);
684 
685             // Category
686 
687             if (!message.isDiscussion()) {
688                 MBCategory category = mbCategoryPersistence.findByPrimaryKey(
689                     message.getCategoryId());
690 
691                 category.setMessageCount(category.getMessageCount() - 1);
692 
693                 mbCategoryPersistence.update(category, false);
694             }
695         }
696 
697         // Tags
698 
699         tagsAssetLocalService.deleteAsset(
700             MBMessage.class.getName(), message.getMessageId());
701 
702         // Social
703 
704         socialActivityLocalService.deleteActivities(
705             MBMessage.class.getName(), message.getMessageId());
706 
707         // Ratings
708 
709         ratingsStatsLocalService.deleteStats(
710             MBMessage.class.getName(), message.getMessageId());
711 
712         // Statistics
713 
714         if (!message.isDiscussion()) {
715             mbStatsUserLocalService.updateStatsUser(
716                 message.getGroupId(), message.getUserId());
717         }
718 
719         // Message flags
720 
721         mbMessageFlagPersistence.removeByMessageId(message.getMessageId());
722 
723         // Resources
724 
725         if (!message.isDiscussion()) {
726             resourceLocalService.deleteResource(
727                 message.getCompanyId(), MBMessage.class.getName(),
728                 ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
729         }
730 
731         // Message
732 
733         mbMessagePersistence.remove(message);
734     }
735 
736     public List<MBMessage> getCategoryMessages(
737             long categoryId, int start, int end)
738         throws SystemException {
739 
740         return mbMessagePersistence.findByCategoryId(categoryId, start, end);
741     }
742 
743     public List<MBMessage> getCategoryMessages(
744             long categoryId, int start, int end, OrderByComparator obc)
745         throws SystemException {
746 
747         return mbMessagePersistence.findByCategoryId(
748             categoryId, start, end, obc);
749     }
750 
751     public int getCategoryMessagesCount(long categoryId)
752         throws SystemException {
753 
754         return mbMessagePersistence.countByCategoryId(categoryId);
755     }
756 
757     public List<MBMessage> getCompanyMessages(
758             long companyId, int start, int end)
759         throws SystemException {
760 
761         return mbMessagePersistence.findByCompanyId(companyId, start, end);
762     }
763 
764     public List<MBMessage> getCompanyMessages(
765             long companyId, int start, int end, OrderByComparator obc)
766         throws SystemException {
767 
768         return mbMessagePersistence.findByCompanyId(companyId, start, end, obc);
769     }
770 
771     public int getCompanyMessagesCount(long companyId)
772         throws SystemException {
773 
774         return mbMessagePersistence.countByCompanyId(companyId);
775     }
776 
777     public MBMessageDisplay getDiscussionMessageDisplay(
778             long userId, String className, long classPK)
779         throws PortalException, SystemException {
780 
781         return getDiscussionMessageDisplay(
782             userId, className, classPK, MBThreadImpl.THREAD_VIEW_COMBINATION);
783     }
784 
785     public MBMessageDisplay getDiscussionMessageDisplay(
786             long userId, String className, long classPK, String threadView)
787         throws PortalException, SystemException {
788 
789         long classNameId = PortalUtil.getClassNameId(className);
790 
791         MBMessage message = null;
792 
793         MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
794             classNameId, classPK);
795 
796         if (discussion != null) {
797             List<MBMessage> messages = mbMessagePersistence.findByT_P(
798                 discussion.getThreadId(),
799                 MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID);
800 
801             message = messages.get(0);
802         }
803         else {
804             String subject = String.valueOf(classPK);
805             //String body = subject;
806 
807             try {
808                 message = addDiscussionMessage(
809                     userId, null, className, classPK, 0,
810                     MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID, subject, subject,
811                     new ServiceContext());
812             }
813             catch (SystemException se) {
814                 if (_log.isWarnEnabled()) {
815                     _log.warn(
816                         "Add failed, fetch {threadId=0, parentMessageId=" +
817                             MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID + "}");
818                 }
819 
820                 List<MBMessage> messages = mbMessagePersistence.findByT_P(
821                     0, MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID);
822 
823                 if (messages.isEmpty()) {
824                     throw se;
825                 }
826 
827                 message = messages.get(0);
828             }
829         }
830 
831         return getMessageDisplay(message, threadView);
832     }
833 
834     public int getDiscussionMessagesCount(long classNameId, long classPK)
835         throws SystemException {
836 
837         MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
838             classNameId, classPK);
839 
840         if (discussion == null) {
841             return 0;
842         }
843 
844         int count = mbMessagePersistence.countByThreadId(
845             discussion.getThreadId());
846 
847         if (count >= 1) {
848             return count - 1;
849         }
850         else {
851             return 0;
852         }
853     }
854 
855     public List<MBDiscussion> getDiscussions(String className)
856         throws SystemException {
857 
858         long classNameId = PortalUtil.getClassNameId(className);
859 
860         return mbDiscussionPersistence.findByClassNameId(classNameId);
861     }
862 
863     public List<MBMessage> getGroupMessages(long groupId, int start, int end)
864         throws SystemException {
865 
866         return mbMessagePersistence.findByGroupId(groupId, start, end);
867     }
868 
869     public List<MBMessage> getGroupMessages(
870             long groupId, int start, int end, OrderByComparator obc)
871         throws SystemException {
872 
873         return mbMessagePersistence.findByGroupId(groupId, start, end, obc);
874     }
875 
876     public List<MBMessage> getGroupMessages(
877             long groupId, long userId, int start, int end)
878         throws SystemException {
879 
880         return mbMessagePersistence.findByG_U(groupId, userId, start, end);
881     }
882 
883     public List<MBMessage> getGroupMessages(
884             long groupId, long userId, int start, int end,
885             OrderByComparator obc)
886         throws SystemException {
887 
888         return mbMessagePersistence.findByG_U(groupId, userId, start, end, obc);
889     }
890 
891     public int getGroupMessagesCount(long groupId) throws SystemException {
892         return mbMessagePersistence.countByGroupId(groupId);
893     }
894 
895     public int getGroupMessagesCount(long groupId, long userId)
896         throws SystemException {
897 
898         return mbMessagePersistence.countByG_U(groupId, userId);
899     }
900 
901     public MBMessage getMessage(long messageId)
902         throws PortalException, SystemException {
903 
904         return mbMessagePersistence.findByPrimaryKey(messageId);
905     }
906 
907     public MBMessageDisplay getMessageDisplay(long messageId, String threadView)
908         throws PortalException, SystemException {
909 
910         MBMessage message = getMessage(messageId);
911 
912         return getMessageDisplay(message, threadView);
913     }
914 
915     public MBMessageDisplay getMessageDisplay(
916             MBMessage message, String threadView)
917         throws PortalException, SystemException {
918 
919         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
920             message.getCategoryId());
921 
922         MBMessage parentMessage = null;
923 
924         if (message.isReply()) {
925             parentMessage = mbMessagePersistence.findByPrimaryKey(
926                 message.getParentMessageId());
927         }
928 
929         MBThread thread = mbThreadPersistence.findByPrimaryKey(
930             message.getThreadId());
931 
932         if (!message.isDiscussion()) {
933             mbThreadLocalService.updateThread(
934                 thread.getThreadId(), thread.getViewCount() + 1);
935         }
936 
937         ThreadLastPostDateComparator comparator =
938             new ThreadLastPostDateComparator(false);
939 
940         MBThread[] prevAndNextThreads =
941             mbThreadPersistence.findByCategoryId_PrevAndNext(
942                 message.getThreadId(), message.getCategoryId(), comparator);
943 
944         MBThread previousThread = prevAndNextThreads[0];
945         MBThread nextThread = prevAndNextThreads[2];
946 
947         return new MBMessageDisplayImpl(
948             message, parentMessage, category, thread,
949             previousThread, nextThread, threadView);
950     }
951 
952     public List<MBMessage> getMessages(String className, long classPK)
953         throws SystemException {
954 
955         long classNameId = PortalUtil.getClassNameId(className);
956 
957         return mbMessagePersistence.findByC_C(classNameId, classPK);
958     }
959 
960     public List<MBMessage> getNoAssetMessages() throws SystemException {
961         return mbMessageFinder.findByNoAssets();
962     }
963 
964     public int getPositionInThread(long messageId)
965         throws PortalException, SystemException {
966 
967         MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
968 
969         return mbMessageFinder.countByC_T(
970             message.getCreateDate(), message.getThreadId());
971     }
972 
973     public List<MBMessage> getThreadMessages(long threadId)
974         throws SystemException {
975 
976         return getThreadMessages(threadId, new MessageThreadComparator());
977     }
978 
979     public List<MBMessage> getThreadMessages(
980             long threadId, Comparator<MBMessage> comparator)
981         throws SystemException {
982 
983         List<MBMessage> messages = mbMessagePersistence.findByThreadId(
984             threadId);
985 
986         return ListUtil.sort(messages, comparator);
987     }
988 
989     public List<MBMessage> getThreadMessages(long threadId, int start, int end)
990         throws SystemException {
991 
992         return mbMessagePersistence.findByThreadId(threadId, start, end);
993     }
994 
995     public int getThreadMessagesCount(long threadId) throws SystemException {
996         return mbMessagePersistence.countByThreadId(threadId);
997     }
998 
999     public List<MBMessage> getThreadRepliesMessages(
1000            long threadId, int start, int end)
1001        throws SystemException {
1002
1003        return mbMessagePersistence.findByThreadReplies(threadId, start, end);
1004    }
1005
1006    public void reIndex(long messageId) throws SystemException {
1007        if (SearchEngineUtil.isIndexReadOnly()) {
1008            return;
1009        }
1010
1011        MBMessage message = mbMessagePersistence.fetchByPrimaryKey(messageId);
1012
1013        if (message == null) {
1014            return;
1015        }
1016
1017        if (message.isRoot()) {
1018            List<MBMessage> messages = mbMessagePersistence.findByThreadId(
1019                message.getThreadId());
1020
1021            for (MBMessage curMessage : messages) {
1022                reIndex(curMessage);
1023            }
1024        }
1025        else {
1026            reIndex(message);
1027        }
1028    }
1029
1030    public void reIndex(MBMessage message) throws SystemException {
1031        if (message.isDiscussion()) {
1032            return;
1033        }
1034
1035        long companyId = message.getCompanyId();
1036        long groupId = message.getGroupId();
1037        long userId = message.getUserId();
1038        String userName = message.getUserName();
1039        long categoryId = message.getCategoryId();
1040        long threadId = message.getThreadId();
1041        long messageId = message.getMessageId();
1042        String title = message.getSubject();
1043        String content = message.getBody();
1044        boolean anonymous = message.isAnonymous();
1045        Date modifiedDate = message.getModifiedDate();
1046
1047        String[] tagsEntries = tagsEntryLocalService.getEntryNames(
1048            MBMessage.class.getName(), messageId);
1049
1050        ExpandoBridge expandoBridge = message.getExpandoBridge();
1051
1052        try {
1053            Indexer.updateMessage(
1054                companyId, groupId, userId, userName, categoryId, threadId,
1055                messageId, title, content, anonymous, modifiedDate, tagsEntries,
1056                expandoBridge);
1057        }
1058        catch (SearchException se) {
1059            _log.error("Reindexing " + messageId, se);
1060        }
1061    }
1062
1063    public void subscribeMessage(long userId, long messageId)
1064        throws PortalException, SystemException {
1065
1066        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1067
1068        subscriptionLocalService.addSubscription(
1069            userId, MBThread.class.getName(), message.getThreadId());
1070    }
1071
1072    public void unsubscribeMessage(long userId, long messageId)
1073        throws PortalException, SystemException {
1074
1075        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1076
1077        subscriptionLocalService.deleteSubscription(
1078            userId, MBThread.class.getName(), message.getThreadId());
1079    }
1080
1081    public MBMessage updateDiscussionMessage(
1082            long userId, long messageId, String subject, String body)
1083        throws PortalException, SystemException {
1084
1085        if (Validator.isNull(subject)) {
1086            subject = "N/A";
1087        }
1088
1089        List<ObjectValuePair<String, byte[]>> files =
1090            new ArrayList<ObjectValuePair<String, byte[]>>();
1091        List<String> existingFiles = new ArrayList<String>();
1092        double priority = 0.0;
1093        ServiceContext serviceContext = new ServiceContext();
1094
1095        return updateMessage(
1096            userId, messageId, subject, body, files, existingFiles, priority,
1097            serviceContext);
1098    }
1099
1100    public MBMessage updateMessage(
1101            long messageId, Date createDate, Date modifiedDate)
1102        throws PortalException, SystemException {
1103
1104        // Message
1105
1106        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1107
1108        message.setCreateDate(createDate);
1109        message.setModifiedDate(modifiedDate);
1110
1111        mbMessagePersistence.update(message, false);
1112
1113        // Thread
1114
1115        MBThread thread = mbThreadPersistence.findByPrimaryKey(
1116            message.getThreadId());
1117
1118        if (message.isAnonymous()) {
1119            thread.setLastPostByUserId(0);
1120        }
1121        else {
1122            thread.setLastPostByUserId(message.getUserId());
1123        }
1124
1125        thread.setLastPostDate(modifiedDate);
1126
1127        mbThreadPersistence.update(thread, false);
1128
1129        if (!message.isDiscussion()) {
1130
1131            // Category
1132
1133            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
1134                message.getCategoryId());
1135
1136            category.setLastPostDate(modifiedDate);
1137
1138            mbCategoryPersistence.update(category, false);
1139
1140            // Statistics
1141
1142            mbStatsUserLocalService.updateStatsUser(
1143                message.getGroupId(), message.getUserId(), modifiedDate);
1144        }
1145
1146        return message;
1147    }
1148
1149    public MBMessage updateMessage(
1150            long userId, long messageId, String subject, String body,
1151            List<ObjectValuePair<String, byte[]>> files,
1152            List<String> existingFiles, double priority,
1153            ServiceContext serviceContext)
1154        throws PortalException, SystemException {
1155
1156        // Message
1157
1158        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1159
1160        MBCategory category = message.getCategory();
1161        subject = ModelHintsUtil.trimString(
1162            MBMessage.class.getName(), "subject", subject);
1163        Date now = new Date();
1164
1165        validate(subject, body);
1166
1167        message.setModifiedDate(now);
1168        message.setSubject(subject);
1169        message.setBody(body);
1170        message.setAttachments(!files.isEmpty() || !existingFiles.isEmpty());
1171
1172        if (priority != MBThreadImpl.PRIORITY_NOT_GIVEN) {
1173            message.setPriority(priority);
1174        }
1175
1176        // Attachments
1177
1178        long companyId = message.getCompanyId();
1179        String portletId = CompanyConstants.SYSTEM_STRING;
1180        long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1181        long repositoryId = CompanyConstants.SYSTEM;
1182        String dirName = message.getAttachmentsDir();
1183
1184        if (!files.isEmpty() || !existingFiles.isEmpty()) {
1185            try {
1186                dlService.addDirectory(companyId, repositoryId, dirName);
1187            }
1188            catch (DuplicateDirectoryException dde) {
1189            }
1190
1191            String[] fileNames = dlService.getFileNames(
1192                companyId, repositoryId, dirName);
1193
1194            for (String fileName: fileNames) {
1195                if (!existingFiles.contains(fileName)) {
1196                    dlService.deleteFile(
1197                        companyId, portletId, repositoryId, fileName);
1198                }
1199            }
1200
1201            for (int i = 0; i < files.size(); i++) {
1202                ObjectValuePair<String, byte[]> ovp = files.get(i);
1203
1204                String fileName = ovp.getKey();
1205                byte[] bytes = ovp.getValue();
1206
1207                try {
1208                    dlService.addFile(
1209                        companyId, portletId, groupId, repositoryId,
1210                        dirName + "/" + fileName, 0, StringPool.BLANK,
1211                        message.getModifiedDate(), new String[0], new String[0],
1212                        bytes);
1213                }
1214                catch (DuplicateFileException dfe) {
1215                }
1216            }
1217        }
1218        else {
1219            try {
1220                dlService.deleteDirectory(
1221                    companyId, portletId, repositoryId, dirName);
1222            }
1223            catch (NoSuchDirectoryException nsde) {
1224            }
1225        }
1226
1227        mbMessagePersistence.update(message, false);
1228
1229        // Thread
1230
1231        MBThread thread = mbThreadPersistence.findByPrimaryKey(
1232            message.getThreadId());
1233
1234        if ((priority != MBThreadImpl.PRIORITY_NOT_GIVEN) &&
1235            (thread.getPriority() != priority)) {
1236
1237            thread.setPriority(priority);
1238
1239            mbThreadPersistence.update(thread, false);
1240
1241            updatePriorities(thread.getThreadId(), priority);
1242        }
1243
1244        // Category
1245
1246        if (!message.isDiscussion()) {
1247            category.setLastPostDate(now);
1248
1249            mbCategoryPersistence.update(category, false);
1250        }
1251
1252        // Subscriptions
1253
1254        notifySubscribers(category, message, serviceContext, true);
1255
1256        // Tags
1257
1258        updateTagsAsset(userId, message, serviceContext.getTagsEntries());
1259
1260        // Indexer
1261
1262        reIndex(message);
1263
1264        return message;
1265    }
1266
1267    public MBMessage updateMessage(long messageId, String body)
1268        throws PortalException, SystemException {
1269
1270        MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1271
1272        message.setBody(body);
1273
1274        mbMessagePersistence.update(message, false);
1275
1276        return message;
1277    }
1278
1279    public void updateTagsAsset(
1280            long userId, MBMessage message, String[] tagsEntries)
1281        throws PortalException, SystemException {
1282
1283        if (message.isDiscussion()) {
1284            return;
1285        }
1286
1287        tagsAssetLocalService.updateAsset(
1288            userId, message.getGroupId(), MBMessage.class.getName(),
1289            message.getMessageId(), null, tagsEntries, true, null, null, null,
1290            null, ContentTypes.TEXT_HTML, message.getSubject(), null, null,
1291            null, 0, 0, null, false);
1292    }
1293
1294    protected void deleteDiscussionSocialActivities(
1295            String className, List<MBMessage> messages)
1296        throws PortalException, SystemException {
1297
1298        if (messages.size() == 0) {
1299            return;
1300        }
1301
1302        MBMessage message = messages.get(0);
1303
1304        MBDiscussion discussion = mbDiscussionPersistence.findByThreadId(
1305            message.getThreadId());
1306
1307        long classNameId = PortalUtil.getClassNameId(className);
1308        long classPK = discussion.getClassPK();
1309
1310        if (discussion.getClassNameId() != classNameId) {
1311            return;
1312        }
1313
1314        Set<Long> messageIds = new HashSet<Long>();
1315
1316        for (MBMessage curMessage : messages) {
1317            messageIds.add(curMessage.getMessageId());
1318        }
1319
1320        List<SocialActivity> socialActivities =
1321            socialActivityLocalService.getActivities(
1322                0, className, classPK, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
1323
1324        for (SocialActivity socialActivity : socialActivities) {
1325            if (Validator.isNull(socialActivity.getExtraData())) {
1326                continue;
1327            }
1328
1329            JSONObject extraData = JSONFactoryUtil.createJSONObject(
1330                socialActivity.getExtraData());
1331
1332            long extraDataMessageId = extraData.getLong("messageId");
1333
1334            if (messageIds.contains(extraDataMessageId)) {
1335                socialActivityLocalService.deleteActivity(
1336                    socialActivity.getActivityId());
1337            }
1338        }
1339    }
1340
1341    protected void notifySubscribers(
1342            MBCategory category, MBMessage message,
1343            ServiceContext serviceContext, boolean update)
1344        throws PortalException, SystemException {
1345
1346        String layoutFullURL = serviceContext.getLayoutFullURL();
1347
1348        if (Validator.isNull(layoutFullURL) || category.isDiscussion()) {
1349            return;
1350        }
1351
1352        PortletPreferences preferences =
1353            ServiceContextUtil.getPortletPreferences(serviceContext);
1354
1355        if (preferences == null) {
1356            long ownerId = category.getGroupId();
1357            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1358            long plid = PortletKeys.PREFS_PLID_SHARED;
1359            String portletId = PortletKeys.MESSAGE_BOARDS;
1360            String defaultPreferences = null;
1361
1362            preferences = portletPreferencesLocalService.getPreferences(
1363                category.getCompanyId(), ownerId, ownerType, plid, portletId,
1364                defaultPreferences);
1365        }
1366
1367        if (!update && MBUtil.getEmailMessageAddedEnabled(preferences)) {
1368        }
1369        else if (update && MBUtil.getEmailMessageUpdatedEnabled(preferences)) {
1370        }
1371        else {
1372            return;
1373        }
1374
1375        Company company = companyPersistence.findByPrimaryKey(
1376            message.getCompanyId());
1377
1378        Group group = groupPersistence.findByPrimaryKey(category.getGroupId());
1379
1380        String emailAddress = StringPool.BLANK;
1381        String fullName = message.getUserName();
1382
1383        try {
1384            User user = userPersistence.findByPrimaryKey(message.getUserId());
1385
1386            emailAddress = user.getEmailAddress();
1387            fullName = user.getFullName();
1388        }
1389        catch (NoSuchUserException nsue) {
1390        }
1391
1392        if (message.isAnonymous()) {
1393            emailAddress = StringPool.BLANK;
1394            fullName = LanguageUtil.get(
1395                ServiceContextUtil.getLocale(serviceContext), "anonymous");
1396        }
1397
1398        List<Long> categoryIds = new ArrayList<Long>();
1399
1400        categoryIds.add(category.getCategoryId());
1401        categoryIds.addAll(category.getAncestorCategoryIds());
1402
1403        String messageURL =
1404            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR +
1405                "message_boards/message/" + message.getMessageId();
1406
1407        String portletName = PortalUtil.getPortletTitle(
1408            PortletKeys.MESSAGE_BOARDS, LocaleUtil.getDefault());
1409
1410        String fromName = MBUtil.getEmailFromName(preferences);
1411        String fromAddress = MBUtil.getEmailFromAddress(preferences);
1412
1413        String mailingListAddress = StringPool.BLANK;
1414
1415        if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
1416            mailingListAddress = MBUtil.getMailingListAddress(
1417                message.getCategoryId(), message.getMessageId(),
1418                company.getMx(), fromAddress);
1419        }
1420
1421        String replyToAddress = mailingListAddress;
1422        String mailId = MBUtil.getMailId(
1423            company.getMx(), message.getCategoryId(), message.getMessageId());
1424
1425        fromName = StringUtil.replace(
1426            fromName,
1427            new String[] {
1428                "[$COMPANY_ID$]",
1429                "[$COMPANY_MX$]",
1430                "[$COMPANY_NAME$]",
1431                "[$COMMUNITY_NAME$]",
1432                "[$MAILING_LIST_ADDRESS$]",
1433                "[$MESSAGE_USER_ADDRESS$]",
1434                "[$MESSAGE_USER_NAME$]",
1435                "[$PORTLET_NAME$]"
1436            },
1437            new String[] {
1438                String.valueOf(company.getCompanyId()),
1439                company.getMx(),
1440                company.getName(),
1441                group.getName(),
1442                mailingListAddress,
1443                emailAddress,
1444                fullName,
1445                portletName
1446            });
1447
1448        fromAddress = StringUtil.replace(
1449            fromAddress,
1450            new String[] {
1451                "[$COMPANY_ID$]",
1452                "[$COMPANY_MX$]",
1453                "[$COMPANY_NAME$]",
1454                "[$COMMUNITY_NAME$]",
1455                "[$MAILING_LIST_ADDRESS$]",
1456                "[$MESSAGE_USER_ADDRESS$]",
1457                "[$MESSAGE_USER_NAME$]",
1458                "[$PORTLET_NAME$]"
1459            },
1460            new String[] {
1461                String.valueOf(company.getCompanyId()),
1462                company.getMx(),
1463                company.getName(),
1464                group.getName(),
1465                mailingListAddress,
1466                emailAddress,
1467                fullName,
1468                portletName
1469            });
1470
1471        String subjectPrefix = null;
1472        String body = null;
1473        String signature = null;
1474        boolean htmlFormat = MBUtil.getEmailHtmlFormat(preferences);
1475
1476        if (update) {
1477            subjectPrefix = MBUtil.getEmailMessageUpdatedSubjectPrefix(
1478                preferences);
1479            body = MBUtil.getEmailMessageUpdatedBody(preferences);
1480            signature = MBUtil.getEmailMessageUpdatedSignature(preferences);
1481        }
1482        else {
1483            subjectPrefix = MBUtil.getEmailMessageAddedSubjectPrefix(
1484                preferences);
1485            body = MBUtil.getEmailMessageAddedBody(preferences);
1486            signature = MBUtil.getEmailMessageAddedSignature(preferences);
1487        }
1488
1489        if (Validator.isNotNull(signature)) {
1490            body +=  "\n--\n" + signature;
1491        }
1492
1493        subjectPrefix = StringUtil.replace(
1494            subjectPrefix,
1495            new String[] {
1496                "[$CATEGORY_NAME$]",
1497                "[$COMPANY_ID$]",
1498                "[$COMPANY_MX$]",
1499                "[$COMPANY_NAME$]",
1500                "[$COMMUNITY_NAME$]",
1501                "[$FROM_ADDRESS$]",
1502                "[$FROM_NAME$]",
1503                "[$MAILING_LIST_ADDRESS$]",
1504                "[$MESSAGE_BODY$]",
1505                "[$MESSAGE_ID$]",
1506                "[$MESSAGE_SUBJECT$]",
1507                "[$MESSAGE_USER_ADDRESS$]",
1508                "[$MESSAGE_USER_NAME$]",
1509                "[$PORTAL_URL$]",
1510                "[$PORTLET_NAME$]"
1511            },
1512            new String[] {
1513                category.getName(),
1514                String.valueOf(company.getCompanyId()),
1515                company.getMx(),
1516                company.getName(),
1517                group.getName(),
1518                fromAddress,
1519                fromName,
1520                mailingListAddress,
1521                message.getBody(),
1522                String.valueOf(message.getMessageId()),
1523                message.getSubject(),
1524                emailAddress,
1525                fullName,
1526                company.getVirtualHost(),
1527                portletName
1528            });
1529
1530        body = StringUtil.replace(
1531            body,
1532            new String[] {
1533                "[$CATEGORY_NAME$]",
1534                "[$COMPANY_ID$]",
1535                "[$COMPANY_MX$]",
1536                "[$COMPANY_NAME$]",
1537                "[$COMMUNITY_NAME$]",
1538                "[$FROM_ADDRESS$]",
1539                "[$FROM_NAME$]",
1540                "[$MAILING_LIST_ADDRESS$]",
1541                "[$MESSAGE_BODY$]",
1542                "[$MESSAGE_ID$]",
1543                "[$MESSAGE_SUBJECT$]",
1544                "[$MESSAGE_URL$]",
1545                "[$MESSAGE_USER_ADDRESS$]",
1546                "[$MESSAGE_USER_NAME$]",
1547                "[$PORTAL_URL$]",
1548                "[$PORTLET_NAME$]"
1549            },
1550            new String[] {
1551                category.getName(),
1552                String.valueOf(company.getCompanyId()),
1553                company.getMx(),
1554                company.getName(),
1555                group.getName(),
1556                fromAddress,
1557                fromName,
1558                mailingListAddress,
1559                message.getBody(),
1560                String.valueOf(message.getMessageId()),
1561                message.getSubject(),
1562                messageURL,
1563                emailAddress,
1564                fullName,
1565                company.getVirtualHost(),
1566                portletName
1567            });
1568
1569        String subject = message.getSubject();
1570
1571        if (subject.indexOf(subjectPrefix) == -1) {
1572            subject = subjectPrefix.trim() + " " + subject.trim();
1573        }
1574
1575        String inReplyTo = null;
1576
1577        if (message.getParentMessageId() !=
1578                MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID) {
1579
1580            inReplyTo = MBUtil.getMailId(
1581                company.getMx(), message.getCategoryId(),
1582                message.getParentMessageId());
1583        }
1584
1585        com.liferay.portal.kernel.messaging.Message messagingObj =
1586            new com.liferay.portal.kernel.messaging.Message();
1587
1588        messagingObj.put("companyId", message.getCompanyId());
1589        messagingObj.put("userId", message.getUserId());
1590        messagingObj.put("groupId", message.getGroupId());
1591        messagingObj.put("categoryIds", StringUtil.merge(categoryIds));
1592        messagingObj.put("threadId", message.getThreadId());
1593        messagingObj.put("fromName", fromName);
1594        messagingObj.put("fromAddress", fromAddress);
1595        messagingObj.put("subject", subject);
1596        messagingObj.put("body", body);
1597        messagingObj.put("replyToAddress", replyToAddress);
1598        messagingObj.put("mailId", mailId);
1599        messagingObj.put("inReplyTo", inReplyTo);
1600        messagingObj.put("htmlFormat", htmlFormat);
1601        messagingObj.put(
1602            "sourceMailingList", MailingListThreadLocal.isSourceMailingList());
1603
1604        MessageBusUtil.sendMessage(
1605            DestinationNames.MESSAGE_BOARDS, messagingObj);
1606    }
1607
1608    protected void sendBlogsCommentsEmail(
1609            long userId, BlogsEntry entry, MBMessage message,
1610            ServiceContext serviceContext)
1611        throws IOException, PortalException, SystemException {
1612
1613        long companyId = message.getCompanyId();
1614
1615        if (!PrefsPropsUtil.getBoolean(
1616                companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_ENABLED)) {
1617
1618            return;
1619        }
1620
1621        String layoutFullURL = serviceContext.getLayoutFullURL();
1622
1623        String blogsEntryURL =
1624            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1625                entry.getUrlTitle();
1626
1627        User blogsUser = userPersistence.findByPrimaryKey(entry.getUserId());
1628        User commentsUser = userPersistence.findByPrimaryKey(userId);
1629
1630        String fromName = PrefsPropsUtil.getString(
1631            companyId, PropsKeys.ADMIN_EMAIL_FROM_NAME);
1632        String fromAddress = PrefsPropsUtil.getString(
1633            companyId, PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);
1634
1635        String toName = blogsUser.getFullName();
1636        String toAddress = blogsUser.getEmailAddress();
1637
1638        String subject = PrefsPropsUtil.getContent(
1639            companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_SUBJECT);
1640        String body = PrefsPropsUtil.getContent(
1641            companyId, PropsKeys.BLOGS_EMAIL_COMMENTS_ADDED_BODY);
1642
1643        subject = StringUtil.replace(
1644            subject,
1645            new String[] {
1646                "[$BLOGS_COMMENTS_BODY$]",
1647                "[$BLOGS_COMMENTS_USER_ADDRESS$]",
1648                "[$BLOGS_COMMENTS_USER_NAME$]",
1649                "[$BLOGS_ENTRY_URL$]",
1650                "[$FROM_ADDRESS$]",
1651                "[$FROM_NAME$]",
1652                "[$TO_ADDRESS$]",
1653                "[$TO_NAME$]"
1654            },
1655            new String[] {
1656                message.getBody(),
1657                commentsUser.getEmailAddress(),
1658                commentsUser.getFullName(),
1659                blogsEntryURL,
1660                fromAddress,
1661                fromName,
1662                toAddress,
1663                toName
1664            });
1665
1666        body = StringUtil.replace(
1667            body,
1668            new String[] {
1669                "[$BLOGS_COMMENTS_BODY$]",
1670                "[$BLOGS_COMMENTS_USER_ADDRESS$]",
1671                "[$BLOGS_COMMENTS_USER_NAME$]",
1672                "[$BLOGS_ENTRY_URL$]",
1673                "[$FROM_ADDRESS$]",
1674                "[$FROM_NAME$]",
1675                "[$TO_ADDRESS$]",
1676                "[$TO_NAME$]"
1677            },
1678            new String[] {
1679                message.getBody(),
1680                commentsUser.getEmailAddress(),
1681                commentsUser.getFullName(),
1682                blogsEntryURL,
1683                fromAddress,
1684                fromName,
1685                toAddress,
1686                toName
1687            });
1688
1689        InternetAddress from = new InternetAddress(fromAddress, fromName);
1690
1691        InternetAddress to = new InternetAddress(toAddress, toName);
1692
1693        MailMessage mailMessage = new MailMessage(
1694            from, to, subject, body, true);
1695
1696        mailService.sendEmail(mailMessage);
1697    }
1698
1699    protected void updatePriorities(long threadId, double priority)
1700        throws SystemException {
1701
1702        List<MBMessage> messages = mbMessagePersistence.findByThreadId(
1703            threadId);
1704
1705        for (MBMessage message : messages) {
1706            if (message.getPriority() != priority) {
1707                message.setPriority(priority);
1708
1709                mbMessagePersistence.update(message, false);
1710            }
1711        }
1712    }
1713
1714    protected void validate(String subject, String body)
1715        throws PortalException {
1716
1717        if (Validator.isNull(subject)) {
1718            throw new MessageSubjectException();
1719        }
1720
1721        if (Validator.isNull(body)) {
1722            throw new MessageBodyException();
1723        }
1724    }
1725
1726    private static Log _log = LogFactoryUtil.getLog(
1727        MBMessageLocalServiceImpl.class);
1728
1729}