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