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