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