001
014
015 package com.liferay.portal.util;
016
017 import com.liferay.mail.model.Attachment;
018 import com.liferay.mail.service.MailServiceUtil;
019 import com.liferay.portal.NoSuchUserException;
020 import com.liferay.portal.kernel.exception.PortalException;
021 import com.liferay.portal.kernel.exception.SystemException;
022 import com.liferay.portal.kernel.log.Log;
023 import com.liferay.portal.kernel.log.LogFactoryUtil;
024 import com.liferay.portal.kernel.mail.MailMessage;
025 import com.liferay.portal.kernel.mail.SMTPAccount;
026 import com.liferay.portal.kernel.messaging.DestinationNames;
027 import com.liferay.portal.kernel.messaging.MessageBusUtil;
028 import com.liferay.portal.kernel.util.GetterUtil;
029 import com.liferay.portal.kernel.util.HtmlUtil;
030 import com.liferay.portal.kernel.util.LocaleUtil;
031 import com.liferay.portal.kernel.util.ObjectValuePair;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.StringUtil;
034 import com.liferay.portal.kernel.util.Validator;
035 import com.liferay.portal.model.Company;
036 import com.liferay.portal.model.Group;
037 import com.liferay.portal.model.LayoutConstants;
038 import com.liferay.portal.model.Subscription;
039 import com.liferay.portal.model.User;
040 import com.liferay.portal.service.CompanyLocalServiceUtil;
041 import com.liferay.portal.service.GroupLocalServiceUtil;
042 import com.liferay.portal.service.LayoutServiceUtil;
043 import com.liferay.portal.service.SubscriptionLocalServiceUtil;
044 import com.liferay.portal.service.UserLocalServiceUtil;
045
046 import java.io.File;
047 import java.io.Serializable;
048
049 import java.util.ArrayList;
050 import java.util.HashMap;
051 import java.util.HashSet;
052 import java.util.List;
053 import java.util.Locale;
054 import java.util.Map;
055 import java.util.Set;
056
057 import javax.mail.internet.InternetAddress;
058
059
062 public class SubscriptionSender implements Serializable {
063
064 public void addAttachment(File file) {
065 addAttachment(file, null);
066 }
067
068 public void addAttachment(File file, String fileName) {
069 if (file == null) {
070 return;
071 }
072
073 if (attachments == null) {
074 attachments = new ArrayList<Attachment>();
075 }
076
077 Attachment attachment = new Attachment(file, fileName);
078
079 attachments.add(attachment);
080 }
081
082 public void addPersistedSubscribers(String className, long classPK) {
083 ObjectValuePair<String, Long> ovp = new ObjectValuePair<String, Long>(
084 className, classPK);
085
086 _persistestedSubscribersOVPs.add(ovp);
087 }
088
089 public void addRuntimeSubscribers(String toAddress, String toName) {
090 ObjectValuePair<String, String> ovp =
091 new ObjectValuePair<String, String>(toAddress, toName);
092
093 _runtimeSubscribersOVPs.add(ovp);
094 }
095
096 public void flushNotifications() throws Exception {
097 initialize();
098
099 Thread currentThread = Thread.currentThread();
100
101 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
102
103 try {
104 if ((_classLoader != null) &&
105 (contextClassLoader != _classLoader)) {
106
107 currentThread.setContextClassLoader(_classLoader);
108 }
109
110 for (ObjectValuePair<String, Long> ovp :
111 _persistestedSubscribersOVPs) {
112
113 String className = ovp.getKey();
114 long classPK = ovp.getValue();
115
116 List<Subscription> subscriptions =
117 SubscriptionLocalServiceUtil.getSubscriptions(
118 companyId, className, classPK);
119
120 for (Subscription subscription : subscriptions) {
121 try {
122 notifySubscriber(subscription);
123 }
124 catch (PortalException pe) {
125 _log.error(
126 "Unable to process subscription: " + subscription);
127
128 continue;
129 }
130 }
131
132 if (bulk) {
133 Locale locale = LocaleUtil.getDefault();
134
135 InternetAddress to = new InternetAddress(
136 replaceContent(replyToAddress, locale),
137 replaceContent(replyToAddress, locale));
138
139 sendEmail(to, locale);
140 }
141 }
142
143 _persistestedSubscribersOVPs.clear();
144
145 for (ObjectValuePair<String, String> ovp :
146 _runtimeSubscribersOVPs) {
147
148 String toAddress = ovp.getKey();
149 String toName = ovp.getValue();
150
151 if (_sentEmailAddresses.contains(toAddress)) {
152 if (_log.isDebugEnabled()) {
153 _log.debug(
154 "Do not send a duplicate email to " + toAddress);
155 }
156
157 return;
158 }
159 else {
160 if (_log.isDebugEnabled()) {
161 _log.debug(
162 "Add " + toAddress + " to the list of users who " +
163 "have received an email");
164 }
165
166 _sentEmailAddresses.add(toAddress);
167 }
168
169 InternetAddress to = new InternetAddress(toAddress, toName);
170
171 sendEmail(to, LocaleUtil.getDefault());
172 }
173
174 _runtimeSubscribersOVPs.clear();
175 }
176 finally {
177 if ((_classLoader != null) &&
178 (contextClassLoader != _classLoader)) {
179
180 currentThread.setContextClassLoader(contextClassLoader);
181 }
182 }
183 }
184
185 public void flushNotificationsAsync() {
186 Thread currentThread = Thread.currentThread();
187
188 _classLoader = currentThread.getContextClassLoader();
189
190 MessageBusUtil.sendMessage(DestinationNames.SUBSCRIPTION_SENDER, this);
191 }
192
193 public Object getContextAttribute(String key) {
194 return _context.get(key);
195 }
196
197 public void initialize() throws PortalException, SystemException {
198 if (_initialized) {
199 return;
200 }
201
202 _initialized = true;
203
204 Company company = CompanyLocalServiceUtil.getCompany(companyId);
205
206 setContextAttribute("[$COMPANY_ID$]", company.getCompanyId());
207 setContextAttribute("[$COMPANY_MX$]", company.getMx());
208 setContextAttribute("[$COMPANY_NAME$]", company.getName());
209 setContextAttribute("[$PORTAL_URL$]", company.getVirtualHostname());
210
211 if (groupId > 0) {
212 Group group = GroupLocalServiceUtil.getGroup(groupId);
213
214 setContextAttribute("[$SITE_NAME$]", group.getDescriptiveName());
215 }
216
217 if ((userId > 0) && Validator.isNotNull(_contextUserPrefix)) {
218 setContextAttribute(
219 "[$" + _contextUserPrefix + "_USER_ADDRESS$]",
220 HtmlUtil.escape(PortalUtil.getUserEmailAddress(userId)));
221 setContextAttribute(
222 "[$" + _contextUserPrefix + "_USER_NAME$]",
223 HtmlUtil.escape(
224 PortalUtil.getUserName(userId, StringPool.BLANK)));
225 }
226
227 mailId = PortalUtil.getMailId(
228 company.getMx(), _mailIdPopPortletPrefix, _mailIdIds);
229 }
230
231 public String getMailId() {
232 return this.mailId;
233 }
234
235 public void setBody(String body) {
236 this.body = body;
237 }
238
239 public void setBulk(boolean bulk) {
240 this.bulk = bulk;
241 }
242
243 public void setCompanyId(long companyId) {
244 this.companyId = companyId;
245 }
246
247 public void setContextAttribute(String key, Object value) {
248 _context.put(key, HtmlUtil.escape(String.valueOf(value)));
249 }
250
251 public void setContextAttributes(Object... values) {
252 for (int i = 0; i < values.length; i += 2) {
253 setContextAttribute(String.valueOf(values[i]), values[i + 1]);
254 }
255 }
256
257 public void setContextUserPrefix(String contextUserPrefix) {
258 _contextUserPrefix = contextUserPrefix;
259 }
260
261 public void setFrom(String fromAddress, String fromName) {
262 this.fromAddress = fromAddress;
263 this.fromName = fromName;
264 }
265
266 public void setGroupId(long groupId) {
267 this.groupId = groupId;
268 }
269
270 public void setHtmlFormat(boolean htmlFormat) {
271 this.htmlFormat = htmlFormat;
272 }
273
274 public void setInReplyTo(String inReplyTo) {
275 this.inReplyTo = inReplyTo;
276 }
277
278 public void setLocalizedBodyMap(Map<Locale, String> localizedBodyMap) {
279 this.localizedBodyMap = localizedBodyMap;
280 }
281
282 public void setLocalizedSubjectMap(
283 Map<Locale, String> localizedSubjectMap) {
284
285 this.localizedSubjectMap = localizedSubjectMap;
286 }
287
288 public void setMailId(String popPortletPrefix, Object... ids) {
289 _mailIdPopPortletPrefix = popPortletPrefix;
290 _mailIdIds = ids;
291 }
292
293 public void setPortletId(String portletId) {
294 this.portletId = portletId;
295 }
296
297 public void setReplyToAddress(String replyToAddress) {
298 this.replyToAddress = replyToAddress;
299 }
300
301
305 public void setScopeGroupId(long scopeGroupId) {
306 try {
307 Group group = GroupLocalServiceUtil.getGroup(scopeGroupId);
308
309 if (group.isLayout()) {
310 groupId = group.getParentGroupId();
311 }
312 else {
313 groupId = scopeGroupId;
314 }
315 }
316 catch (Exception e) {
317 }
318
319 this.scopeGroupId = scopeGroupId;
320 }
321
322 public void setSMTPAccount(SMTPAccount smtpAccount) {
323 this.smtpAccount = smtpAccount;
324 }
325
326 public void setSubject(String subject) {
327 this.subject = subject;
328 }
329
330 public void setUserId(long userId) {
331 this.userId = userId;
332 }
333
334 protected void deleteSubscription(Subscription subscription)
335 throws Exception {
336
337 SubscriptionLocalServiceUtil.deleteSubscription(
338 subscription.getSubscriptionId());
339 }
340
341 protected boolean hasPermission(Subscription subscription, User user)
342 throws Exception {
343
344 return _PERMISSION;
345 }
346
347 protected void notifySubscriber(Subscription subscription)
348 throws Exception {
349
350 User user = null;
351
352 try {
353 user = UserLocalServiceUtil.getUserById(subscription.getUserId());
354 }
355 catch (NoSuchUserException nsue) {
356 if (_log.isInfoEnabled()) {
357 _log.info(
358 "Subscription " + subscription.getSubscriptionId() +
359 " is stale and will be deleted");
360 }
361
362 deleteSubscription(subscription);
363
364 return;
365 }
366
367 String emailAddress = user.getEmailAddress();
368
369 if (_sentEmailAddresses.contains(emailAddress)) {
370 if (_log.isDebugEnabled()) {
371 _log.debug(
372 "Do not send a duplicate email to " + emailAddress);
373 }
374
375 return;
376 }
377 else {
378 if (_log.isDebugEnabled()) {
379 _log.debug(
380 "Add " + emailAddress +
381 " to the list of users who have received an email");
382 }
383
384 _sentEmailAddresses.add(emailAddress);
385 }
386
387 if (!user.isActive()) {
388 if (_log.isDebugEnabled()) {
389 _log.debug("Skip inactive user " + user.getUserId());
390 }
391
392 return;
393 }
394
395 if (groupId > 0) {
396 Group group = GroupLocalServiceUtil.getGroup(groupId);
397
398 if (!GroupLocalServiceUtil.hasUserGroup(
399 user.getUserId(), groupId) &&
400 !group.isCompany() &&
401 (LayoutServiceUtil.getDefaultPlid(
402 groupId, scopeGroupId, false, portletId) ==
403 LayoutConstants.DEFAULT_PLID)) {
404
405 if (_log.isInfoEnabled()) {
406 _log.info(
407 "Subscription " + subscription.getSubscriptionId() +
408 " is stale and will be deleted");
409 }
410
411 deleteSubscription(subscription);
412
413 return;
414 }
415 }
416
417 try {
418 if (!hasPermission(subscription, user)) {
419 if (_log.isDebugEnabled()) {
420 _log.debug("Skip unauthorized user " + user.getUserId());
421 }
422
423 return;
424 }
425 }
426 catch (Exception e) {
427 _log.error(e, e);
428
429 return;
430 }
431
432 if (bulk) {
433 InternetAddress bulkAddress = new InternetAddress(
434 user.getEmailAddress(), user.getFullName());
435
436 if (_bulkAddresses == null) {
437 _bulkAddresses = new ArrayList<InternetAddress>();
438 }
439
440 _bulkAddresses.add(bulkAddress);
441 }
442 else {
443 try {
444 InternetAddress to = new InternetAddress(
445 user.getEmailAddress(), user.getFullName());
446
447 sendEmail(to, user.getLocale());
448 }
449 catch (Exception e) {
450 _log.error(e, e);
451 }
452 }
453 }
454
455 protected void processMailMessage(MailMessage mailMessage, Locale locale)
456 throws Exception {
457
458 InternetAddress from = mailMessage.getFrom();
459 InternetAddress to = mailMessage.getTo()[0];
460
461 String processedSubject = StringUtil.replace(
462 mailMessage.getSubject(),
463 new String[] {
464 "[$FROM_ADDRESS$]",
465 "[$FROM_NAME$]",
466 "[$TO_ADDRESS$]",
467 "[$TO_NAME$]"
468 },
469 new String[] {
470 from.getAddress(),
471 GetterUtil.getString(from.getPersonal(), from.getAddress()),
472 HtmlUtil.escape(to.getAddress()),
473 HtmlUtil.escape(
474 GetterUtil.getString(to.getPersonal(), to.getAddress()))
475 });
476
477 processedSubject = replaceContent(processedSubject, locale);
478
479 mailMessage.setSubject(processedSubject);
480
481 String processedBody = StringUtil.replace(
482 mailMessage.getBody(),
483 new String[] {
484 "[$FROM_ADDRESS$]",
485 "[$FROM_NAME$]",
486 "[$TO_ADDRESS$]",
487 "[$TO_NAME$]"
488 },
489 new String[] {
490 from.getAddress(),
491 GetterUtil.getString(from.getPersonal(), from.getAddress()),
492 HtmlUtil.escape(to.getAddress()),
493 HtmlUtil.escape(
494 GetterUtil.getString(to.getPersonal(), to.getAddress()))
495 });
496
497 processedBody = replaceContent(processedBody, locale);
498
499 mailMessage.setBody(processedBody);
500 }
501
502 protected String replaceContent(String content, Locale locale)
503 throws Exception {
504
505 for (Map.Entry<String, Object> entry : _context.entrySet()) {
506 String key = entry.getKey();
507 Object value = entry.getValue();
508
509 content = StringUtil.replace(content, key, String.valueOf(value));
510 }
511
512 if (Validator.isNotNull(portletId)) {
513 String portletName = PortalUtil.getPortletTitle(portletId, locale);
514
515 content = StringUtil.replace(
516 content, "[$PORTLET_NAME$]", portletName);
517 }
518
519 return content;
520 }
521
522 protected void sendEmail(InternetAddress to, Locale locale)
523 throws Exception {
524
525 InternetAddress from = new InternetAddress(
526 replaceContent(fromAddress, locale),
527 replaceContent(fromName, locale));
528
529 String processedSubject = null;
530
531 if (localizedSubjectMap != null) {
532 String localizedSubject = localizedSubjectMap.get(locale);
533
534 if (Validator.isNull(localizedSubject)) {
535 Locale defaultLocale = LocaleUtil.getDefault();
536
537 processedSubject = localizedSubjectMap.get(defaultLocale);
538 }
539 else {
540 processedSubject = localizedSubject;
541 }
542 }
543 else {
544 processedSubject = this.subject;
545 }
546
547 String processedBody = null;
548
549 if (localizedBodyMap != null) {
550 String localizedBody = localizedBodyMap.get(locale);
551
552 if (Validator.isNull(localizedBody)) {
553 Locale defaultLocale = LocaleUtil.getDefault();
554
555 processedBody = localizedBodyMap.get(defaultLocale);
556 }
557 else {
558 processedBody = localizedBody;
559 }
560 }
561 else {
562 processedBody = this.body;
563 }
564
565 MailMessage mailMessage = new MailMessage(
566 from, to, processedSubject, processedBody, htmlFormat);
567
568 if (attachments != null) {
569 for (Attachment attachment : attachments) {
570 mailMessage.addAttachment(
571 attachment.getFile(), attachment.getFileName());
572 }
573 }
574
575 if (bulk && (_bulkAddresses != null)) {
576 mailMessage.setBulkAddresses(
577 _bulkAddresses.toArray(
578 new InternetAddress[_bulkAddresses.size()]));
579
580 _bulkAddresses.clear();
581 }
582
583 if (inReplyTo != null) {
584 mailMessage.setInReplyTo(inReplyTo);
585 }
586
587 mailMessage.setMessageId(mailId);
588
589 if (replyToAddress != null) {
590 InternetAddress replyTo = new InternetAddress(
591 replaceContent(replyToAddress, locale),
592 replaceContent(replyToAddress, locale));
593
594 mailMessage.setReplyTo(new InternetAddress[] {replyTo});
595 }
596
597 if (smtpAccount != null) {
598 mailMessage.setSMTPAccount(smtpAccount);
599 }
600
601 processMailMessage(mailMessage, locale);
602
603 MailServiceUtil.sendEmail(mailMessage);
604 }
605
606 protected List<Attachment> attachments = new ArrayList<Attachment>();
607 protected String body;
608 protected boolean bulk;
609 protected long companyId;
610 protected String fromAddress;
611 protected String fromName;
612 protected long groupId;
613 protected boolean htmlFormat;
614 protected String inReplyTo;
615 protected Map<Locale, String> localizedBodyMap;
616 protected Map<Locale, String> localizedSubjectMap;
617 protected String mailId;
618 protected String portletId;
619 protected String replyToAddress;
620 protected long scopeGroupId;
621 protected SMTPAccount smtpAccount;
622 protected String subject;
623 protected long userId;
624
625 private static final boolean _PERMISSION = true;
626
627 private static Log _log = LogFactoryUtil.getLog(SubscriptionSender.class);
628
629 private List<InternetAddress> _bulkAddresses;
630 private ClassLoader _classLoader;
631 private Map<String, Object> _context = new HashMap<String, Object>();
632 private String _contextUserPrefix;
633 private boolean _initialized;
634 private Object[] _mailIdIds;
635 private String _mailIdPopPortletPrefix;
636 private List<ObjectValuePair<String, Long>> _persistestedSubscribersOVPs =
637 new ArrayList<ObjectValuePair<String, Long>>();
638 private List<ObjectValuePair<String, String>> _runtimeSubscribersOVPs =
639 new ArrayList<ObjectValuePair<String, String>>();
640 private Set<String> _sentEmailAddresses = new HashSet<String>();
641
642 }