ru.mystamps.web.service.MailServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ru.mystamps.web.service.MailServiceImpl.java

Source

/*
 * Copyright (C) 2009-2017 Slava Semushin <slava.semushin@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package ru.mystamps.web.service;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.commons.lang3.time.DatePrinter;
import org.apache.commons.lang3.time.FastDateFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.context.MessageSource;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.scheduling.annotation.Async;

import ru.mystamps.web.Url;
import ru.mystamps.web.service.dto.AdminDailyReport;
import ru.mystamps.web.service.dto.SendUsersActivationDto;
import ru.mystamps.web.service.exception.EmailSendingException;

public class MailServiceImpl implements MailService {
    private static final Logger LOG = LoggerFactory.getLogger(MailServiceImpl.class);

    private final JavaMailSender mailer;
    private final MessageSource messageSource;
    private final String adminEmail;
    private final Locale adminLang;
    private final String robotEmail;
    private final boolean testMode;
    private final DatePrinter shortDatePrinter;

    public MailServiceImpl(JavaMailSender mailer, MessageSource messageSource, String adminEmail, Locale adminLang,
            String robotEmail, boolean testMode) {

        this.mailer = mailer;
        this.messageSource = messageSource;
        this.adminEmail = adminEmail;
        this.adminLang = adminLang;
        this.robotEmail = robotEmail;
        this.testMode = testMode;

        this.shortDatePrinter = FastDateFormat.getInstance("dd.MM.yyyy", adminLang);
    }

    @Override
    @Async
    public void sendActivationKeyToUser(SendUsersActivationDto activation) {
        Validate.isTrue(activation != null, "Activation must be non null");
        Validate.isTrue(activation.getEmail() != null, "E-mail must be non null");
        Validate.isTrue(activation.getLang() != null, "Language must be non null");
        Validate.isTrue(activation.getActivationKey() != null, "Activation key must be non null");

        sendMail(activation.getEmail(), getSubjectOfActivationMail(activation), getTextOfActivationMail(activation),
                "activation_key");

        LOG.info("Email with activation code has been sent to {} (lang: {})", activation.getEmail(),
                activation.getLang());
    }

    @Override
    @Async
    public void sendDailyStatisticsToAdmin(AdminDailyReport report) {
        sendMail(adminEmail, getSubjectOfDailyStatisticsMail(report), getTextOfDailyStatisticsMail(report),
                "daily_statistics");

        String date = shortDatePrinter.format(report.getStartDate());

        LOG.info("E-mail with daily statistics for {} has been sent to {} (lang: {})", date, adminEmail, adminLang);
    }

    @SuppressWarnings("PMD.UseObjectForClearerAPI")
    private void sendMail(final String email, final String subject, final String text, final String tag) {

        try {
            // We're using MimeMessagePreparator only because of its capability of adding headers.
            // Otherwise we would use SimpleMailMessage class.
            MimeMessagePreparator preparator = new MimeMessagePreparator() {
                @Override
                @SuppressWarnings("PMD.SignatureDeclareThrowsException")
                public void prepare(MimeMessage mimeMessage) throws Exception {
                    MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
                    message.setValidateAddresses(true);
                    message.setTo(email);
                    message.setFrom(new InternetAddress(robotEmail, "My Stamps", "UTF-8"));
                    message.setSubject(subject);
                    message.setText(text);

                    // see: http://documentation.mailgun.com/user_manual.html#sending-via-smtp
                    message.getMimeMessage().addHeader("X-Mailgun-Tag", tag);
                    if (testMode) {
                        message.getMimeMessage().addHeader("X-Mailgun-Drop-Message", "yes");
                    }
                }
            };

            mailer.send(preparator);

        } catch (MailException ex) {
            throw new EmailSendingException("Can't send mail to e-mail " + email, ex);
        }
    }

    private String getTextOfActivationMail(SendUsersActivationDto activation) {
        String template = messageSource.getMessage("activation.text", null, activation.getLocale());

        String activationUrl = String.format("%s?key=%s", Url.ACTIVATE_ACCOUNT_PAGE, activation.getActivationKey());

        Map<String, String> ctx = new HashMap<>();
        ctx.put("site_url", testMode ? Url.SITE : Url.PUBLIC_URL);
        ctx.put("activation_url_with_key", activationUrl);
        ctx.put("expire_after_days", String.valueOf(CronService.PURGE_AFTER_DAYS));

        StrSubstitutor substitutor = new StrSubstitutor(ctx);
        return substitutor.replace(template);
    }

    private String getSubjectOfActivationMail(SendUsersActivationDto activation) {
        return messageSource.getMessage("activation.subject", null, activation.getLocale());
    }

    private String getSubjectOfDailyStatisticsMail(AdminDailyReport report) {
        String template = messageSource.getMessage("daily_stat.subject", null, adminLang);

        String fromDate = shortDatePrinter.format(report.getStartDate());
        Map<String, String> ctx = new HashMap<>();
        ctx.put("date", fromDate);
        put(ctx, "total_changes", report.countTotalChanges());

        StrSubstitutor substitutor = new StrSubstitutor(ctx);
        return substitutor.replace(template);
    }

    private String getTextOfDailyStatisticsMail(AdminDailyReport report) {
        String template = messageSource.getMessage("daily_stat.text", null, adminLang);
        String fromDate = shortDatePrinter.format(report.getStartDate());
        String tillDate = shortDatePrinter.format(report.getEndDate());

        Map<String, String> ctx = new HashMap<>();
        ctx.put("from_date", fromDate);
        ctx.put("to_date", tillDate);

        put(ctx, "added_countries_cnt", report.getAddedCountriesCounter());
        put(ctx, "untranslated_countries_cnt", report.getUntranslatedCountriesCounter());
        put(ctx, "added_categories_cnt", report.getAddedCategoriesCounter());
        put(ctx, "untranslated_categories_cnt", report.getUntranslatedCategoriesCounter());
        put(ctx, "added_series_cnt", report.getAddedSeriesCounter());
        put(ctx, "updated_series_cnt", report.getUpdatedSeriesCounter());
        put(ctx, "updated_collections_cnt", report.getUpdatedCollectionsCounter());
        put(ctx, "registration_requests_cnt", report.getRegistrationRequestsCounter());
        put(ctx, "registered_users_cnt", report.getRegisteredUsersCounter());
        put(ctx, "events_cnt", report.countEvents());
        put(ctx, "not_found_cnt", report.getNotFoundCounter());
        put(ctx, "failed_auth_cnt", report.getFailedAuthCounter());
        put(ctx, "missing_csrf_cnt", report.getMissingCsrfCounter());
        put(ctx, "invalid_csrf_cnt", report.getInvalidCsrfCounter());
        put(ctx, "bad_request_cnt", -1L); // TODO: #122

        return new StrSubstitutor(ctx).replace(template);
    }

    private static void put(Map<String, String> ctx, String key, long value) {
        ctx.put(key, String.valueOf(value));
    }

}