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