001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.mail.model.FileAttachment;
018    import com.liferay.mail.service.MailServiceUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
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.notifications.UserNotificationManagerUtil;
029    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
030    import com.liferay.portal.kernel.util.ArrayUtil;
031    import com.liferay.portal.kernel.util.ClassLoaderPool;
032    import com.liferay.portal.kernel.util.EscapableObject;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.HtmlEscapableObject;
035    import com.liferay.portal.kernel.util.HtmlUtil;
036    import com.liferay.portal.kernel.util.LocaleUtil;
037    import com.liferay.portal.kernel.util.ObjectValuePair;
038    import com.liferay.portal.kernel.util.StringPool;
039    import com.liferay.portal.kernel.util.StringUtil;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
042    import com.liferay.portal.model.Company;
043    import com.liferay.portal.model.Group;
044    import com.liferay.portal.model.ResourceAction;
045    import com.liferay.portal.model.Subscription;
046    import com.liferay.portal.model.User;
047    import com.liferay.portal.model.UserNotificationDeliveryConstants;
048    import com.liferay.portal.security.permission.ActionKeys;
049    import com.liferay.portal.security.permission.BaseModelPermissionCheckerUtil;
050    import com.liferay.portal.security.permission.PermissionChecker;
051    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
052    import com.liferay.portal.service.CompanyLocalServiceUtil;
053    import com.liferay.portal.service.GroupLocalServiceUtil;
054    import com.liferay.portal.service.ResourceActionLocalServiceUtil;
055    import com.liferay.portal.service.ServiceContext;
056    import com.liferay.portal.service.SubscriptionLocalServiceUtil;
057    import com.liferay.portal.service.UserLocalServiceUtil;
058    import com.liferay.portal.service.UserNotificationEventLocalServiceUtil;
059    
060    import java.io.File;
061    import java.io.IOException;
062    import java.io.ObjectInputStream;
063    import java.io.ObjectOutputStream;
064    import java.io.Serializable;
065    
066    import java.util.ArrayList;
067    import java.util.HashMap;
068    import java.util.HashSet;
069    import java.util.List;
070    import java.util.Locale;
071    import java.util.Map;
072    import java.util.Set;
073    import java.util.concurrent.Callable;
074    
075    import javax.mail.internet.InternetAddress;
076    
077    /**
078     * @author Brian Wing Shun Chan
079     * @author Mate Thurzo
080     * @author Raymond Aug??
081     * @author Sergio Gonz??lez
082     * @author Roberto D??az
083     */
084    public class SubscriptionSender implements Serializable {
085    
086            public void addFileAttachment(File file) {
087                    addFileAttachment(file, null);
088            }
089    
090            public void addFileAttachment(File file, String fileName) {
091                    if (file == null) {
092                            return;
093                    }
094    
095                    if (fileAttachments == null) {
096                            fileAttachments = new ArrayList<>();
097                    }
098    
099                    FileAttachment attachment = new FileAttachment(file, fileName);
100    
101                    fileAttachments.add(attachment);
102            }
103    
104            public void addPersistedSubscribers(String className, long classPK) {
105                    ObjectValuePair<String, Long> ovp = new ObjectValuePair<>(
106                            className, classPK);
107    
108                    _persistestedSubscribersOVPs.add(ovp);
109            }
110    
111            public void addRuntimeSubscribers(String toAddress, String toName) {
112                    ObjectValuePair<String, String> ovp = new ObjectValuePair<>(
113                            toAddress, toName);
114    
115                    _runtimeSubscribersOVPs.add(ovp);
116            }
117    
118            public void flushNotifications() throws Exception {
119                    initialize();
120    
121                    Thread currentThread = Thread.currentThread();
122    
123                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
124    
125                    try {
126                            if ((_classLoader != null) &&
127                                    (contextClassLoader != _classLoader)) {
128    
129                                    currentThread.setContextClassLoader(_classLoader);
130                            }
131    
132                            for (ObjectValuePair<String, Long> ovp :
133                                            _persistestedSubscribersOVPs) {
134    
135                                    String className = ovp.getKey();
136                                    long classPK = ovp.getValue();
137    
138                                    List<Subscription> subscriptions =
139                                            SubscriptionLocalServiceUtil.getSubscriptions(
140                                                    companyId, className, classPK);
141    
142                                    for (Subscription subscription : subscriptions) {
143                                            try {
144                                                    notifyPersistedSubscriber(subscription);
145                                            }
146                                            catch (Exception e) {
147                                                    _log.error(
148                                                            "Unable to process subscription: " + subscription);
149                                            }
150                                    }
151                            }
152    
153                            _persistestedSubscribersOVPs.clear();
154    
155                            for (ObjectValuePair<String, String> ovp :
156                                            _runtimeSubscribersOVPs) {
157    
158                                    String toAddress = ovp.getKey();
159    
160                                    if (Validator.isNull(toAddress)) {
161                                            continue;
162                                    }
163    
164                                    if (_sentEmailAddresses.contains(toAddress)) {
165                                            if (_log.isDebugEnabled()) {
166                                                    _log.debug(
167                                                            "Do not send a duplicate email to " + toAddress);
168                                            }
169    
170                                            continue;
171                                    }
172    
173                                    if (_log.isDebugEnabled()) {
174                                            _log.debug(
175                                                    "Add " + toAddress + " to the list of users who " +
176                                                            "have received an email");
177                                    }
178    
179                                    _sentEmailAddresses.add(toAddress);
180    
181                                    String toName = ovp.getValue();
182    
183                                    InternetAddress to = new InternetAddress(toAddress, toName);
184    
185                                    notifyRuntimeSubscriber(to, LocaleUtil.getDefault());
186                            }
187    
188                            _runtimeSubscribersOVPs.clear();
189    
190                            if (bulk) {
191                                    Locale locale = LocaleUtil.getDefault();
192    
193                                    InternetAddress to = new InternetAddress(
194                                            replaceContent(replyToAddress, locale),
195                                            replaceContent(replyToAddress, locale));
196    
197                                    sendEmail(to, locale);
198                            }
199                    }
200                    finally {
201                            if ((_classLoader != null) &&
202                                    (contextClassLoader != _classLoader)) {
203    
204                                    currentThread.setContextClassLoader(contextClassLoader);
205                            }
206                    }
207            }
208    
209            public void flushNotificationsAsync() {
210                    TransactionCommitCallbackRegistryUtil.registerCallback(
211                            new Callable<Void>() {
212    
213                                    @Override
214                                    public Void call() throws Exception {
215                                            Thread currentThread = Thread.currentThread();
216    
217                                            _classLoader = currentThread.getContextClassLoader();
218    
219                                            MessageBusUtil.sendMessage(
220                                                    DestinationNames.SUBSCRIPTION_SENDER,
221                                                    SubscriptionSender.this);
222    
223                                            return null;
224                                    }
225                            }
226                    );
227            }
228    
229            public Object getContextAttribute(String key) {
230                    return _context.get(key);
231            }
232    
233            public long getCurrentUserId() {
234                    return currentUserId;
235            }
236    
237            public String getMailId() {
238                    return this.mailId;
239            }
240    
241            /**
242             * @deprecated As of 7.0.0, replaced by {@link getCurrentUserId()}
243             */
244            @Deprecated
245            public long getUserId() {
246                    return getCurrentUserId();
247            }
248    
249            public void initialize() throws Exception {
250                    if (_initialized) {
251                            return;
252                    }
253    
254                    _initialized = true;
255    
256                    if ((groupId == 0) && (serviceContext != null)) {
257                            setScopeGroupId(serviceContext.getScopeGroupId());
258                    }
259    
260                    Company company = CompanyLocalServiceUtil.getCompany(companyId);
261    
262                    setContextAttribute("[$COMPANY_ID$]", company.getCompanyId());
263                    setContextAttribute("[$COMPANY_MX$]", company.getMx());
264                    setContextAttribute("[$COMPANY_NAME$]", company.getName());
265                    setContextAttribute("[$PORTAL_URL$]", company.getPortalURL(groupId));
266    
267                    if (groupId > 0) {
268                            Group group = GroupLocalServiceUtil.getGroup(groupId);
269    
270                            setContextAttribute("[$SITE_NAME$]", group.getDescriptiveName());
271                    }
272    
273                    if ((creatorUserId > 0) &&
274                            Validator.isNotNull(_contextCreatorUserPrefix)) {
275    
276                            setContextAttribute(
277                                    "[$" + _contextCreatorUserPrefix + "_USER_ADDRESS$]",
278                                    PortalUtil.getUserEmailAddress(creatorUserId));
279                            setContextAttribute(
280                                    "[$" + _contextCreatorUserPrefix + "_USER_NAME$]",
281                                    PortalUtil.getUserName(creatorUserId, StringPool.BLANK));
282                    }
283    
284                    if (uniqueMailId) {
285                            _mailIdIds = ArrayUtil.append(
286                                    _mailIdIds, PortalUUIDUtil.generate());
287                    }
288    
289                    mailId = PortalUtil.getMailId(
290                            company.getMx(), _mailIdPopPortletPrefix, _mailIdIds);
291            }
292    
293            public void setBody(String body) {
294                    this.body = body;
295            }
296    
297            public void setBulk(boolean bulk) {
298                    this.bulk = bulk;
299            }
300    
301            public void setClassName(String className) {
302                    _className = className;
303            }
304    
305            public void setClassPK(long classPK) {
306                    _classPK = classPK;
307            }
308    
309            public void setCompanyId(long companyId) {
310                    this.companyId = companyId;
311            }
312    
313            public void setContextAttribute(String key, EscapableObject<String> value) {
314                    _context.put(key, value);
315            }
316    
317            public void setContextAttribute(String key, Object value) {
318                    setContextAttribute(key, value, true);
319            }
320    
321            public void setContextAttribute(String key, Object value, boolean escape) {
322                    setContextAttribute(
323                            key,
324                            new HtmlEscapableObject<String>(String.valueOf(value), escape));
325            }
326    
327            public void setContextAttributes(Object... values) {
328                    for (int i = 0; i < values.length; i += 2) {
329                            setContextAttribute(String.valueOf(values[i]), values[i + 1]);
330                    }
331            }
332    
333            public void setContextCreatorUserPrefix(String contextCreatorUserPrefix) {
334                    _contextCreatorUserPrefix = contextCreatorUserPrefix;
335            }
336    
337            public void setCreatorUserId(long creatorUserId) {
338                    this.creatorUserId = creatorUserId;
339            }
340    
341            public void setCurrentUserId(long currentUserId) {
342                    this.currentUserId = currentUserId;
343            }
344    
345            public void setEntryTitle(String entryTitle) {
346                    this._entryTitle = entryTitle;
347            }
348    
349            public void setEntryURL(String entryURL) {
350                    _entryURL = entryURL;
351            }
352    
353            public void setFrom(String fromAddress, String fromName) {
354                    this.fromAddress = fromAddress;
355                    this.fromName = fromName;
356            }
357    
358            public void setGroupId(long groupId) {
359                    this.groupId = groupId;
360            }
361    
362            public void setHtmlFormat(boolean htmlFormat) {
363                    this.htmlFormat = htmlFormat;
364            }
365    
366            public void setInReplyTo(String inReplyTo) {
367                    this.inReplyTo = inReplyTo;
368            }
369    
370            public void setLocalizedBodyMap(Map<Locale, String> localizedBodyMap) {
371                    this.localizedBodyMap = localizedBodyMap;
372            }
373    
374            public void setLocalizedSubjectMap(
375                    Map<Locale, String> localizedSubjectMap) {
376    
377                    this.localizedSubjectMap = localizedSubjectMap;
378            }
379    
380            public void setMailId(String popPortletPrefix, Object... ids) {
381                    _mailIdPopPortletPrefix = popPortletPrefix;
382                    _mailIdIds = ids;
383            }
384    
385            public void setNotificationClassNameId(long notificationClassNameId) {
386                    _notificationClassNameId = notificationClassNameId;
387            }
388    
389            /**
390             * @see com.liferay.portal.kernel.notifications.UserNotificationDefinition
391             */
392            public void setNotificationType(int notificationType) {
393                    _notificationType = notificationType;
394            }
395    
396            public void setPortletId(String portletId) {
397                    this.portletId = portletId;
398            }
399    
400            public void setReplyToAddress(String replyToAddress) {
401                    this.replyToAddress = replyToAddress;
402            }
403    
404            /**
405             * @see com.liferay.portal.kernel.search.BaseIndexer#getSiteGroupId(long)
406             */
407            public void setScopeGroupId(long scopeGroupId) {
408                    try {
409                            Group group = GroupLocalServiceUtil.getGroup(scopeGroupId);
410    
411                            if (group.isLayout()) {
412                                    groupId = group.getParentGroupId();
413                            }
414                            else {
415                                    groupId = scopeGroupId;
416                            }
417                    }
418                    catch (Exception e) {
419                    }
420    
421                    this.scopeGroupId = scopeGroupId;
422            }
423    
424            public void setServiceContext(ServiceContext serviceContext) {
425                    this.serviceContext = serviceContext;
426            }
427    
428            public void setSMTPAccount(SMTPAccount smtpAccount) {
429                    this.smtpAccount = smtpAccount;
430            }
431    
432            public void setSubject(String subject) {
433                    this.subject = subject;
434            }
435    
436            public void setUniqueMailId(boolean uniqueMailId) {
437                    this.uniqueMailId = uniqueMailId;
438            }
439    
440            /**
441             * @deprecated As of 7.0.0, replaced by {@link #setCurrentUserId(long)}
442             */
443            @Deprecated
444            public void setUserId(long userId) {
445                    setCurrentUserId(userId);
446            }
447    
448            protected void deleteSubscription(Subscription subscription)
449                    throws Exception {
450    
451                    SubscriptionLocalServiceUtil.deleteSubscription(
452                            subscription.getSubscriptionId());
453            }
454    
455            protected boolean hasPermission(
456                            Subscription subscription, String className, long classPK,
457                            User user)
458                    throws Exception {
459    
460                    if (subscription.getClassName() == null) {
461                            return false;
462                    }
463    
464                    PermissionChecker permissionChecker =
465                            PermissionCheckerFactoryUtil.create(user);
466    
467                    Boolean hasPermission = null;
468    
469                    if (Validator.isNotNull(className)) {
470                            hasPermission =
471                                    BaseModelPermissionCheckerUtil.containsBaseModelPermission(
472                                            permissionChecker, groupId, className, classPK,
473                                            ActionKeys.VIEW);
474    
475                            if ((hasPermission == null) || !hasPermission) {
476                                    return false;
477                            }
478                    }
479    
480                    hasPermission = hasSubscribePermission(permissionChecker, subscription);
481    
482                    if ((hasPermission == null) || !hasPermission) {
483                            return false;
484                    }
485    
486                    return true;
487            }
488    
489            protected boolean hasPermission(Subscription subscription, User user)
490                    throws Exception {
491    
492                    return hasPermission(subscription, _className, _classPK, user);
493            }
494    
495            /**
496             * @throws PortalException
497             */
498            protected Boolean hasSubscribePermission(
499                            PermissionChecker permissionChecker, Subscription subscription)
500                    throws PortalException {
501    
502                    ResourceAction resourceAction =
503                            ResourceActionLocalServiceUtil.fetchResourceAction(
504                                    subscription.getClassName(), ActionKeys.SUBSCRIBE);
505    
506                    if (resourceAction != null) {
507                            return BaseModelPermissionCheckerUtil.containsBaseModelPermission(
508                                    permissionChecker, groupId, subscription.getClassName(),
509                                    subscription.getClassPK(), ActionKeys.SUBSCRIBE);
510                    }
511    
512                    return Boolean.TRUE;
513            }
514    
515            protected void notifyPersistedSubscriber(Subscription subscription)
516                    throws Exception {
517    
518                    notifyPersistedSubscriber(subscription, _className, _classPK);
519            }
520    
521            protected void notifyPersistedSubscriber(
522                            Subscription subscription, String className, long classPK)
523                    throws Exception {
524    
525                    User user = UserLocalServiceUtil.fetchUserById(
526                            subscription.getUserId());
527    
528                    if (user == null) {
529                            if (_log.isInfoEnabled()) {
530                                    _log.info(
531                                            "Subscription " + subscription.getSubscriptionId() +
532                                                    " is stale and will be deleted");
533                            }
534    
535                            deleteSubscription(subscription);
536    
537                            return;
538                    }
539    
540                    String emailAddress = user.getEmailAddress();
541    
542                    if (_sentEmailAddresses.contains(emailAddress)) {
543                            if (_log.isDebugEnabled()) {
544                                    _log.debug("Do not send a duplicate email to " + emailAddress);
545                            }
546    
547                            return;
548                    }
549                    else {
550                            if (_log.isDebugEnabled()) {
551                                    _log.debug(
552                                            "Add " + emailAddress +
553                                                    " to the list of users who have received an email");
554                            }
555    
556                            _sentEmailAddresses.add(emailAddress);
557                    }
558    
559                    if (!user.isActive()) {
560                            if (_log.isDebugEnabled()) {
561                                    _log.debug("Skip inactive user " + user.getUserId());
562                            }
563    
564                            return;
565                    }
566    
567                    try {
568                            if (!hasPermission(subscription, className, classPK, user)) {
569                                    if (_log.isDebugEnabled()) {
570                                            _log.debug("Skip unauthorized user " + user.getUserId());
571                                    }
572    
573                                    return;
574                            }
575                    }
576                    catch (Exception e) {
577                            _log.error(e, e);
578    
579                            return;
580                    }
581    
582                    sendNotification(user);
583            }
584    
585            protected void notifyRuntimeSubscriber(InternetAddress to, Locale locale)
586                    throws Exception {
587    
588                    String emailAddress = to.getAddress();
589    
590                    User user = UserLocalServiceUtil.fetchUserByEmailAddress(
591                            companyId, emailAddress);
592    
593                    if (user == null) {
594                            if (_log.isInfoEnabled()) {
595                                    _log.info(
596                                            "User with email address " + emailAddress +
597                                                    " does not exist for company " + companyId);
598                            }
599    
600                            if (bulk) {
601                                    if (_bulkAddresses == null) {
602                                            _bulkAddresses = new ArrayList<>();
603                                    }
604    
605                                    _bulkAddresses.add(to);
606    
607                                    return;
608                            }
609    
610                            sendEmail(to, locale);
611                    }
612                    else {
613                            sendNotification(user);
614                    }
615            }
616    
617            /**
618             * @deprecated As of 6.2.0, replaced by {@link
619             *             #notifyPersistedSubscriber(Subscription)}
620             */
621            @Deprecated
622            protected void notifySubscriber(Subscription subscription)
623                    throws Exception {
624    
625                    notifyPersistedSubscriber(subscription, null, 0);
626            }
627    
628            /**
629             * @deprecated As of 7.0.0, replaced by {@link
630             *             #notifyPersistedSubscriber(Subscription)}
631             */
632            @Deprecated
633            protected void notifySubscriber(
634                            Subscription subscription, String inferredClassName,
635                            long inferredClassPK)
636                    throws Exception {
637    
638                    notifyPersistedSubscriber(
639                            subscription, inferredClassName, inferredClassPK);
640            }
641    
642            protected void processMailMessage(MailMessage mailMessage, Locale locale)
643                    throws Exception {
644    
645                    InternetAddress from = mailMessage.getFrom();
646                    InternetAddress to = mailMessage.getTo()[0];
647    
648                    String processedSubject = StringUtil.replace(
649                            mailMessage.getSubject(),
650                            new String[] {
651                                    "[$FROM_ADDRESS$]", "[$FROM_NAME$]", "[$TO_ADDRESS$]",
652                                    "[$TO_NAME$]"
653                            },
654                            new String[] {
655                                    from.getAddress(),
656                                    GetterUtil.getString(from.getPersonal(), from.getAddress()),
657                                    HtmlUtil.escape(to.getAddress()),
658                                    HtmlUtil.escape(
659                                            GetterUtil.getString(to.getPersonal(), to.getAddress()))
660                            });
661    
662                    processedSubject = replaceContent(processedSubject, locale, false);
663    
664                    mailMessage.setSubject(processedSubject);
665    
666                    String processedBody = StringUtil.replace(
667                            mailMessage.getBody(),
668                            new String[] {
669                                    "[$FROM_ADDRESS$]", "[$FROM_NAME$]", "[$TO_ADDRESS$]",
670                                    "[$TO_NAME$]"
671                            },
672                            new String[] {
673                                    from.getAddress(),
674                                    GetterUtil.getString(from.getPersonal(), from.getAddress()),
675                                    HtmlUtil.escape(to.getAddress()),
676                                    HtmlUtil.escape(
677                                            GetterUtil.getString(to.getPersonal(), to.getAddress()))
678                            });
679    
680                    processedBody = replaceContent(processedBody, locale, htmlFormat);
681    
682                    mailMessage.setBody(processedBody);
683            }
684    
685            protected String replaceContent(String content, Locale locale)
686                    throws Exception {
687    
688                    return replaceContent(content, locale, true);
689            }
690    
691            protected String replaceContent(
692                            String content, Locale locale, boolean escape)
693                    throws Exception {
694    
695                    for (Map.Entry<String, EscapableObject<String>> entry :
696                                    _context.entrySet()) {
697    
698                            String key = entry.getKey();
699                            EscapableObject<String> value = entry.getValue();
700    
701                            String valueString = null;
702    
703                            if (escape) {
704                                    valueString = value.getEscapedValue();
705                            }
706                            else {
707                                    valueString = value.getOriginalValue();
708                            }
709    
710                            content = StringUtil.replace(content, key, valueString);
711                    }
712    
713                    if (Validator.isNotNull(portletId)) {
714                            String portletName = PortalUtil.getPortletTitle(portletId, locale);
715    
716                            content = StringUtil.replace(
717                                    content, "[$PORTLET_NAME$]", portletName);
718                    }
719    
720                    Company company = CompanyLocalServiceUtil.getCompany(companyId);
721    
722                    content = StringUtil.replace(
723                            content, new String[] {"href=\"/", "src=\"/"},
724                            new String[] {
725                                    "href=\"" + company.getPortalURL(groupId) + "/",
726                                    "src=\"" + company.getPortalURL(groupId) + "/"
727                            });
728    
729                    return content;
730            }
731    
732            protected void sendEmail(InternetAddress to, Locale locale)
733                    throws Exception {
734    
735                    InternetAddress from = new InternetAddress(
736                            replaceContent(fromAddress, locale),
737                            replaceContent(fromName, locale));
738    
739                    String processedSubject = null;
740    
741                    if (localizedSubjectMap != null) {
742                            String localizedSubject = localizedSubjectMap.get(locale);
743    
744                            if (Validator.isNull(localizedSubject)) {
745                                    Locale defaultLocale = LocaleUtil.getDefault();
746    
747                                    processedSubject = localizedSubjectMap.get(defaultLocale);
748                            }
749                            else {
750                                    processedSubject = localizedSubject;
751                            }
752                    }
753                    else {
754                            processedSubject = this.subject;
755                    }
756    
757                    String processedBody = null;
758    
759                    if (localizedBodyMap != null) {
760                            String localizedBody = localizedBodyMap.get(locale);
761    
762                            if (Validator.isNull(localizedBody)) {
763                                    Locale defaultLocale = LocaleUtil.getDefault();
764    
765                                    processedBody = localizedBodyMap.get(defaultLocale);
766                            }
767                            else {
768                                    processedBody = localizedBody;
769                            }
770                    }
771                    else {
772                            processedBody = this.body;
773                    }
774    
775                    MailMessage mailMessage = new MailMessage(
776                            from, to, processedSubject, processedBody, htmlFormat);
777    
778                    if (fileAttachments != null) {
779                            for (FileAttachment fileAttachment : fileAttachments) {
780                                    mailMessage.addFileAttachment(
781                                            fileAttachment.getFile(), fileAttachment.getFileName());
782                            }
783                    }
784    
785                    if (bulk && (_bulkAddresses != null)) {
786                            mailMessage.setBulkAddresses(
787                                    _bulkAddresses.toArray(
788                                            new InternetAddress[_bulkAddresses.size()]));
789    
790                            _bulkAddresses.clear();
791                    }
792    
793                    if (inReplyTo != null) {
794                            mailMessage.setInReplyTo(inReplyTo);
795                    }
796    
797                    mailMessage.setMessageId(mailId);
798    
799                    if (replyToAddress != null) {
800                            InternetAddress replyTo = new InternetAddress(
801                                    replaceContent(replyToAddress, locale),
802                                    replaceContent(replyToAddress, locale));
803    
804                            mailMessage.setReplyTo(new InternetAddress[] {replyTo});
805                    }
806    
807                    if (smtpAccount != null) {
808                            mailMessage.setSMTPAccount(smtpAccount);
809                    }
810    
811                    processMailMessage(mailMessage, locale);
812    
813                    MailServiceUtil.sendEmail(mailMessage);
814            }
815    
816            protected void sendEmailNotification(User user) throws Exception {
817                    if (UserNotificationManagerUtil.isDeliver(
818                                    user.getUserId(), portletId, _notificationClassNameId,
819                                    _notificationType,
820                                    UserNotificationDeliveryConstants.TYPE_EMAIL)) {
821    
822                            InternetAddress to = new InternetAddress(
823                                    user.getEmailAddress(), user.getFullName());
824    
825                            if (bulk) {
826                                    if (_bulkAddresses == null) {
827                                            _bulkAddresses = new ArrayList<>();
828                                    }
829    
830                                    _bulkAddresses.add(to);
831    
832                                    return;
833                            }
834    
835                            sendEmail(to, user.getLocale());
836                    }
837            }
838    
839            protected void sendNotification(User user) throws Exception {
840                    if (currentUserId == user.getUserId() ) {
841                            if (_log.isDebugEnabled()) {
842                                    _log.debug("Skip user " + currentUserId);
843                            }
844    
845                            return;
846                    }
847    
848                    sendEmailNotification(user);
849                    sendUserNotification(user);
850            }
851    
852            protected void sendUserNotification(User user) throws Exception {
853                    JSONObject notificationEventJSONObject =
854                            JSONFactoryUtil.createJSONObject();
855    
856                    notificationEventJSONObject.put("className", _className);
857                    notificationEventJSONObject.put("classPK", _classPK);
858                    notificationEventJSONObject.put("entryTitle", _entryTitle);
859                    notificationEventJSONObject.put("entryURL", _entryURL);
860                    notificationEventJSONObject.put("notificationType", _notificationType);
861                    notificationEventJSONObject.put("userId", currentUserId);
862    
863                    if (UserNotificationManagerUtil.isDeliver(
864                                    user.getUserId(), portletId, _notificationClassNameId,
865                                    _notificationType,
866                                    UserNotificationDeliveryConstants.TYPE_PUSH)) {
867    
868                            UserNotificationEventLocalServiceUtil.sendUserNotificationEvents(
869                                    user.getUserId(), portletId,
870                                    UserNotificationDeliveryConstants.TYPE_PUSH,
871                                    notificationEventJSONObject);
872                    }
873    
874                    if (UserNotificationManagerUtil.isDeliver(
875                                    user.getUserId(), portletId, _notificationClassNameId,
876                                    _notificationType,
877                                    UserNotificationDeliveryConstants.TYPE_WEBSITE)) {
878    
879                            UserNotificationEventLocalServiceUtil.sendUserNotificationEvents(
880                                    user.getUserId(), portletId,
881                                    UserNotificationDeliveryConstants.TYPE_WEBSITE,
882                                    notificationEventJSONObject);
883                    }
884            }
885    
886            protected String body;
887            protected boolean bulk;
888            protected long companyId;
889            protected long creatorUserId;
890            protected long currentUserId;
891            protected List<FileAttachment> fileAttachments = new ArrayList<>();
892            protected String fromAddress;
893            protected String fromName;
894            protected long groupId;
895            protected boolean htmlFormat;
896            protected String inReplyTo;
897            protected Map<Locale, String> localizedBodyMap;
898            protected Map<Locale, String> localizedSubjectMap;
899            protected String mailId;
900            protected String portletId;
901            protected String replyToAddress;
902            protected long scopeGroupId;
903            protected ServiceContext serviceContext;
904            protected SMTPAccount smtpAccount;
905            protected String subject;
906            protected boolean uniqueMailId = true;
907    
908            private void readObject(ObjectInputStream objectInputStream)
909                    throws ClassNotFoundException, IOException {
910    
911                    objectInputStream.defaultReadObject();
912    
913                    String servletContextName = objectInputStream.readUTF();
914    
915                    if (!servletContextName.isEmpty()) {
916                            _classLoader = ClassLoaderPool.getClassLoader(servletContextName);
917                    }
918            }
919    
920            private void writeObject(ObjectOutputStream objectOutputStream)
921                    throws IOException {
922    
923                    objectOutputStream.defaultWriteObject();
924    
925                    String servletContextName = StringPool.BLANK;
926    
927                    if (_classLoader != null) {
928                            servletContextName = ClassLoaderPool.getContextName(_classLoader);
929                    }
930    
931                    objectOutputStream.writeUTF(servletContextName);
932            }
933    
934            private static final Log _log = LogFactoryUtil.getLog(
935                    SubscriptionSender.class);
936    
937            private List<InternetAddress> _bulkAddresses;
938            private transient ClassLoader _classLoader;
939            private String _className;
940            private long _classPK;
941            private final Map<String, EscapableObject<String>> _context =
942                    new HashMap<>();
943            private String _contextCreatorUserPrefix;
944            private String _entryTitle;
945            private String _entryURL;
946            private boolean _initialized;
947            private Object[] _mailIdIds;
948            private String _mailIdPopPortletPrefix;
949            private long _notificationClassNameId;
950            private int _notificationType;
951            private final List<ObjectValuePair<String, Long>>
952                    _persistestedSubscribersOVPs = new ArrayList<>();
953            private final List<ObjectValuePair<String, String>>
954                    _runtimeSubscribersOVPs = new ArrayList<>();
955            private final Set<String> _sentEmailAddresses = new HashSet<>();
956    
957    }