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