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