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