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