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