2 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1 of the License, or (at your option)
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 package com.liferay.portal.util;
17 import com.liferay.mail.model.FileAttachment;
18 import com.liferay.mail.service.MailServiceUtil;
19 import com.liferay.portal.NoSuchUserException;
20 import com.liferay.portal.kernel.exception.PortalException;
21 import com.liferay.portal.kernel.log.Log;
22 import com.liferay.portal.kernel.log.LogFactoryUtil;
23 import com.liferay.portal.kernel.mail.MailMessage;
24 import com.liferay.portal.kernel.mail.SMTPAccount;
25 import com.liferay.portal.kernel.messaging.DestinationNames;
26 import com.liferay.portal.kernel.messaging.MessageBusUtil;
27 import com.liferay.portal.kernel.util.EscapableObject;
28 import com.liferay.portal.kernel.util.GetterUtil;
29 import com.liferay.portal.kernel.util.HtmlEscapableObject;
30 import com.liferay.portal.kernel.util.HtmlUtil;
31 import com.liferay.portal.kernel.util.LocaleUtil;
32 import com.liferay.portal.kernel.util.ObjectValuePair;
33 import com.liferay.portal.kernel.util.StringPool;
34 import com.liferay.portal.kernel.util.StringUtil;
35 import com.liferay.portal.kernel.util.Validator;
36 import com.liferay.portal.model.Company;
37 import com.liferay.portal.model.Group;
38 import com.liferay.portal.model.Subscription;
39 import com.liferay.portal.model.User;
40 import com.liferay.portal.security.permission.PermissionChecker;
41 import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
42 import com.liferay.portal.service.CompanyLocalServiceUtil;
43 import com.liferay.portal.service.GroupLocalServiceUtil;
44 import com.liferay.portal.service.ServiceContext;
45 import com.liferay.portal.service.SubscriptionLocalServiceUtil;
46 import com.liferay.portal.service.UserLocalServiceUtil;
47 import com.liferay.portal.service.permission.SubscriptionPermissionUtil;
48 import com.pentila.entSavoie.utils.ENTMainUtilsLocalServiceUtil;
51 import java.io.Serializable;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Locale;
60 import javax.mail.internet.InternetAddress;
63 * @author Brian Wing Shun Chan
66 public class SubscriptionSender implements Serializable {
68 public void addFileAttachment(File file) {
69 addFileAttachment(file, null);
72 public void addFileAttachment(File file, String fileName) {
77 if (fileAttachments == null) {
78 fileAttachments = new ArrayList<FileAttachment>();
81 FileAttachment attachment = new FileAttachment(file, fileName);
83 fileAttachments.add(attachment);
86 public void addPersistedSubscribers(String className, long classPK) {
87 ObjectValuePair<String, Long> ovp = new ObjectValuePair<String, Long>(
90 _persistestedSubscribersOVPs.add(ovp);
93 public void addRuntimeSubscribers(String toAddress, String toName) {
94 ObjectValuePair<String, String> ovp =
95 new ObjectValuePair<String, String>(
96 toAddress, HtmlUtil.escape(toName));
98 _runtimeSubscribersOVPs.add(ovp);
101 public void flushNotifications() throws Exception {
104 Thread currentThread = Thread.currentThread();
106 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
109 if ((_classLoader != null) &&
110 (contextClassLoader != _classLoader)) {
112 currentThread.setContextClassLoader(_classLoader);
115 for (ObjectValuePair<String, Long> ovp :
116 _persistestedSubscribersOVPs) {
118 String className = ovp.getKey();
119 long classPK = ovp.getValue();
121 List<Subscription> subscriptions =
122 SubscriptionLocalServiceUtil.getSubscriptions(
123 companyId, className, classPK);
125 for (Subscription subscription : subscriptions) {
127 notifySubscriber(subscription);
129 catch (PortalException pe) {
131 "Unable to process subscription: " + subscription);
138 Locale locale = LocaleUtil.getDefault();
140 InternetAddress to = new InternetAddress(
141 replaceContent(replyToAddress, locale),
142 replaceContent(replyToAddress, locale));
144 sendEmail(to, locale);
148 _persistestedSubscribersOVPs.clear();
150 for (ObjectValuePair<String, String> ovp :
151 _runtimeSubscribersOVPs) {
153 String toAddress = ovp.getKey();
154 String toName = ovp.getValue();
156 if (_sentEmailAddresses.contains(toAddress)) {
157 if (_log.isDebugEnabled()) {
159 "Do not send a duplicate email to " + toAddress);
165 if (_log.isDebugEnabled()) {
167 "Add " + toAddress + " to the list of users who " +
168 "have received an email");
171 _sentEmailAddresses.add(toAddress);
174 InternetAddress to = new InternetAddress(toAddress, toName);
176 sendEmail(to, LocaleUtil.getDefault());
179 _runtimeSubscribersOVPs.clear();
182 if ((_classLoader != null) &&
183 (contextClassLoader != _classLoader)) {
185 currentThread.setContextClassLoader(contextClassLoader);
190 public void flushNotificationsAsync() {
191 Thread currentThread = Thread.currentThread();
193 _classLoader = currentThread.getContextClassLoader();
195 MessageBusUtil.sendMessage(DestinationNames.SUBSCRIPTION_SENDER, this);
198 public Object getContextAttribute(String key) {
199 return _context.get(key);
202 public String getMailId() {
206 public void initialize() throws Exception {
213 Company company = CompanyLocalServiceUtil.getCompany(companyId);
215 setContextAttribute("[$COMPANY_ID$]", company.getCompanyId());
216 setContextAttribute("[$COMPANY_MX$]", company.getMx());
217 setContextAttribute("[$COMPANY_NAME$]", company.getName());
218 setContextAttribute("[$PORTAL_URL$]", getPortalURL(company));
221 Group group = GroupLocalServiceUtil.getGroup(groupId);
223 setContextAttribute("[$SITE_NAME$]", group.getDescriptiveName());
226 if ((userId > 0) && Validator.isNotNull(_contextUserPrefix)) {
228 "[$" + _contextUserPrefix + "_USER_ADDRESS$]",
229 PortalUtil.getUserEmailAddress(userId));
231 "[$" + _contextUserPrefix + "_USER_NAME$]",
232 PortalUtil.getUserName(userId, StringPool.BLANK));
235 mailId = PortalUtil.getMailId(
236 company.getMx(), _mailIdPopPortletPrefix, _mailIdIds);
239 public void setBody(String body) {
243 public void setBulk(boolean bulk) {
247 public void setCompanyId(long companyId) {
248 this.companyId = companyId;
251 public void setContextAttribute(String key, EscapableObject<String> value) {
252 _context.put(key, value);
255 public void setContextAttribute(String key, Object value) {
256 setContextAttribute(key, value, true);
259 public void setContextAttribute(String key, Object value, boolean escape) {
262 new HtmlEscapableObject<String>(String.valueOf(value), escape));
265 public void setContextAttributes(Object... values) {
266 for (int i = 0; i < values.length; i += 2) {
267 setContextAttribute(String.valueOf(values[i]), values[i + 1]);
271 public void setContextUserPrefix(String contextUserPrefix) {
272 _contextUserPrefix = contextUserPrefix;
275 public void setFrom(String fromAddress, String fromName) {
276 this.fromAddress = fromAddress;
277 this.fromName = fromName;
280 public void setGroupId(long groupId) {
281 this.groupId = groupId;
284 public void setHtmlFormat(boolean htmlFormat) {
285 this.htmlFormat = htmlFormat;
288 public void setInReplyTo(String inReplyTo) {
289 this.inReplyTo = inReplyTo;
292 public void setLocalizedBodyMap(Map<Locale, String> localizedBodyMap) {
293 this.localizedBodyMap = localizedBodyMap;
296 public void setLocalizedSubjectMap(
297 Map<Locale, String> localizedSubjectMap) {
299 this.localizedSubjectMap = localizedSubjectMap;
302 public void setMailId(String popPortletPrefix, Object... ids) {
303 _mailIdPopPortletPrefix = popPortletPrefix;
307 public void setPortletId(String portletId) {
308 this.portletId = portletId;
311 public void setReplyToAddress(String replyToAddress) {
312 this.replyToAddress = replyToAddress;
317 * com.liferay.portal.kernel.search.BaseIndexer#getParentGroupId(long)}
319 public void setScopeGroupId(long scopeGroupId) {
321 Group group = GroupLocalServiceUtil.getGroup(scopeGroupId);
323 if (group.isLayout()) {
324 groupId = group.getParentGroupId();
327 groupId = scopeGroupId;
330 catch (Exception e) {
333 this.scopeGroupId = scopeGroupId;
336 public void setServiceContext(ServiceContext serviceContext) {
337 this.serviceContext = serviceContext;
340 public void setSMTPAccount(SMTPAccount smtpAccount) {
341 this.smtpAccount = smtpAccount;
344 public void setSubject(String subject) {
345 this.subject = subject;
348 public void setUserId(long userId) {
349 this.userId = userId;
352 protected void deleteSubscription(Subscription subscription)
355 SubscriptionLocalServiceUtil.deleteSubscription(
356 subscription.getSubscriptionId());
359 protected String getPortalURL(Company company) throws Exception {
360 if (serviceContext != null) {
361 String portalURL = serviceContext.getPortalURL();
363 if (Validator.isNotNull(portalURL)) {
368 return company.getPortalURL(groupId);
371 protected boolean hasPermission(Subscription subscription, User user)
374 PermissionChecker permissionChecker =
375 PermissionCheckerFactoryUtil.create(user);
377 return SubscriptionPermissionUtil.contains(
378 permissionChecker, subscription.getClassName(),
379 subscription.getClassPK());
382 protected void notifySubscriber(Subscription subscription)
388 user = UserLocalServiceUtil.getUserById(subscription.getUserId());
390 catch (NoSuchUserException nsue) {
391 if (_log.isInfoEnabled()) {
393 "Subscription " + subscription.getSubscriptionId() +
394 " is stale and will be deleted");
397 deleteSubscription(subscription);
402 String emailAddress = user.getEmailAddress();
404 if (_sentEmailAddresses.contains(emailAddress)) {
405 if (_log.isDebugEnabled()) {
406 _log.debug("Do not send a duplicate email to " + emailAddress);
412 if (_log.isDebugEnabled()) {
414 "Add " + emailAddress +
415 " to the list of users who have received an email");
418 _sentEmailAddresses.add(emailAddress);
421 if (!user.isActive()) {
422 if (_log.isDebugEnabled()) {
423 _log.debug("Skip inactive user " + user.getUserId());
430 if (!hasPermission(subscription, user)) {
431 if (_log.isDebugEnabled()) {
432 _log.debug("Skip unauthorized user " + user.getUserId());
438 catch (Exception e) {
445 InternetAddress bulkAddress = new InternetAddress(
446 user.getEmailAddress(), user.getFullName());
448 if (_bulkAddresses == null) {
449 _bulkAddresses = new ArrayList<InternetAddress>();
452 _bulkAddresses.add(bulkAddress);
456 // Mail filter : we do not want to send mail to generated email address.
457 if (!user.getEmailAddress().equals(user.getScreenName()+ENTMainUtilsLocalServiceUtil.getENTOrgRootSuffixeMail(user.getCompanyId()))) {
458 InternetAddress to = new InternetAddress(
459 user.getEmailAddress(), user.getFullName());
461 sendEmail(to, user.getLocale());
464 catch (Exception e) {
470 protected void processMailMessage(MailMessage mailMessage, Locale locale)
473 InternetAddress from = mailMessage.getFrom();
474 InternetAddress to = mailMessage.getTo()[0];
476 String processedSubject = StringUtil.replace(
477 mailMessage.getSubject(),
479 "[$FROM_ADDRESS$]", "[$FROM_NAME$]", "[$TO_ADDRESS$]",
484 GetterUtil.getString(from.getPersonal(), from.getAddress()),
485 HtmlUtil.escape(to.getAddress()),
487 GetterUtil.getString(to.getPersonal(), to.getAddress()))
490 processedSubject = replaceContent(processedSubject, locale, false);
492 mailMessage.setSubject(processedSubject);
494 String processedBody = StringUtil.replace(
495 mailMessage.getBody(),
497 "[$FROM_ADDRESS$]", "[$FROM_NAME$]", "[$TO_ADDRESS$]",
502 GetterUtil.getString(from.getPersonal(), from.getAddress()),
503 HtmlUtil.escape(to.getAddress()),
505 GetterUtil.getString(to.getPersonal(), to.getAddress()))
508 processedBody = replaceContent(processedBody, locale, htmlFormat);
510 mailMessage.setBody(processedBody);
513 protected String replaceContent(String content, Locale locale)
516 return replaceContent(content, locale, true);
519 protected String replaceContent(
520 String content, Locale locale, boolean escape)
523 for (Map.Entry<String, EscapableObject<String>> entry :
524 _context.entrySet()) {
526 String key = entry.getKey();
527 EscapableObject<String> value = entry.getValue();
529 String valueString = null;
532 valueString = value.getEscapedValue();
535 valueString = value.getOriginalValue();
538 content = StringUtil.replace(content, key, valueString);
541 if (Validator.isNotNull(portletId)) {
542 String portletName = PortalUtil.getPortletTitle(portletId, locale);
544 content = StringUtil.replace(
545 content, "[$PORTLET_NAME$]", portletName);
548 Company company = CompanyLocalServiceUtil.getCompany(companyId);
550 content = StringUtil.replace(
553 "href=\"/", "src=\"/"
556 "href=\"" + getPortalURL(company) + "/",
557 "src=\"" + getPortalURL(company) + "/"
563 protected void sendEmail(InternetAddress to, Locale locale)
566 InternetAddress from = new InternetAddress(
567 replaceContent(fromAddress, locale),
568 replaceContent(fromName, locale));
570 String processedSubject = null;
572 if (localizedSubjectMap != null) {
573 String localizedSubject = localizedSubjectMap.get(locale);
575 if (Validator.isNull(localizedSubject)) {
576 Locale defaultLocale = LocaleUtil.getDefault();
578 processedSubject = localizedSubjectMap.get(defaultLocale);
581 processedSubject = localizedSubject;
585 processedSubject = this.subject;
588 String processedBody = null;
590 if (localizedBodyMap != null) {
591 String localizedBody = localizedBodyMap.get(locale);
593 if (Validator.isNull(localizedBody)) {
594 Locale defaultLocale = LocaleUtil.getDefault();
596 processedBody = localizedBodyMap.get(defaultLocale);
599 processedBody = localizedBody;
603 processedBody = this.body;
606 MailMessage mailMessage = new MailMessage(
607 from, to, processedSubject, processedBody, htmlFormat);
609 if (fileAttachments != null) {
610 for (FileAttachment fileAttachment : fileAttachments) {
611 mailMessage.addFileAttachment(
612 fileAttachment.getFile(), fileAttachment.getFileName());
616 if (bulk && (_bulkAddresses != null)) {
617 mailMessage.setBulkAddresses(
618 _bulkAddresses.toArray(
619 new InternetAddress[_bulkAddresses.size()]));
621 _bulkAddresses.clear();
624 if (inReplyTo != null) {
625 mailMessage.setInReplyTo(inReplyTo);
628 mailMessage.setMessageId(mailId);
630 if (replyToAddress != null) {
631 InternetAddress replyTo = new InternetAddress(
632 replaceContent(replyToAddress, locale),
633 replaceContent(replyToAddress, locale));
635 mailMessage.setReplyTo(new InternetAddress[] {replyTo});
638 if (smtpAccount != null) {
639 mailMessage.setSMTPAccount(smtpAccount);
642 processMailMessage(mailMessage, locale);
644 MailServiceUtil.sendEmail(mailMessage);
647 protected String body;
648 protected boolean bulk;
649 protected long companyId;
650 protected List<FileAttachment> fileAttachments =
651 new ArrayList<FileAttachment>();
652 protected String fromAddress;
653 protected String fromName;
654 protected long groupId;
655 protected boolean htmlFormat;
656 protected String inReplyTo;
657 protected Map<Locale, String> localizedBodyMap;
658 protected Map<Locale, String> localizedSubjectMap;
659 protected String mailId;
660 protected String portletId;
661 protected String replyToAddress;
662 protected long scopeGroupId;
663 protected ServiceContext serviceContext;
664 protected SMTPAccount smtpAccount;
665 protected String subject;
666 protected long userId;
668 private static Log _log = LogFactoryUtil.getLog(SubscriptionSender.class);
670 private List<InternetAddress> _bulkAddresses;
671 private ClassLoader _classLoader;
672 private Map<String, EscapableObject<String>> _context =
673 new HashMap<String, EscapableObject<String>>();
674 private String _contextUserPrefix;
675 private boolean _initialized;
676 private Object[] _mailIdIds;
677 private String _mailIdPopPortletPrefix;
678 private List<ObjectValuePair<String, Long>> _persistestedSubscribersOVPs =
679 new ArrayList<ObjectValuePair<String, Long>>();
680 private List<ObjectValuePair<String, String>> _runtimeSubscribersOVPs =
681 new ArrayList<ObjectValuePair<String, String>>();
682 private Set<String> _sentEmailAddresses = new HashSet<String>();