org.sofun.platform.notification.NotificationServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.sofun.platform.notification.NotificationServiceImpl.java

Source

/*
 * Copyright (c)  Sofun Gaming SAS.
 * Copyright (c)  Julien Anguenot <julien@anguenot.org>
 * Copyright (c)  Julien De Preaumont <juliendepreaumont@gmail.com>
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Julien Anguenot <julien@anguenot.org> - initial API and implementation
*/

package org.sofun.platform.notification;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.Map;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
import org.apache.velocity.runtime.resource.util.StringResourceRepository;
import org.sofun.core.CoreConstants;
import org.sofun.core.api.exception.CoreException;
import org.sofun.core.api.local.NotificationServiceLocal;
import org.sofun.core.api.member.Member;
import org.sofun.core.api.notification.NotificationService;
import org.sofun.core.api.remote.NotificationServiceRemote;
import org.sofun.platform.notification.api.MemberNotification;

/**
 * Notification Service Implementation
 * 
 * @author <a href="mailto:julien@anguenot.org">Julien Anguenot</a>
 * 
 */
@Stateless
@Local(NotificationServiceLocal.class)
@Remote(NotificationServiceRemote.class)
public class NotificationServiceImpl implements NotificationService {

    private static final long serialVersionUID = 1515902405562945152L;

    private static final Log log = LogFactory.getLog(NotificationServiceImpl.class);

    private static final String TEMPLATE_PROPERTIES = "/mail-templates/templates.properties";

    private static final String[] LOCALES = new String[] { "en", "fr" };

    @PersistenceContext(unitName = CoreConstants.PERSISTENCE_UNIT)
    private transient EntityManager em;

    @Resource(mappedName = "java:Mail")
    private transient Session mailer;

    private transient VelocityEngine velocityEngine;

    private transient StringResourceRepository templateRepository;

    public NotificationServiceImpl() {
        super();
    }

    public NotificationServiceImpl(EntityManager em) {
        this();
        this.em = em;
    }

    protected Query createQuery(String queryStr) {
        Query query = em.createQuery(queryStr);
        return query;
    }

    @Override
    public Map<String, Boolean> getNotificationsSchemeFor(Member member) {

        String queryStr = "from " + MemberNotificationImpl.class.getSimpleName()
                + " l where l.member.email =:email";
        Query query = createQuery(queryStr);
        query.setParameter("email", member.getEmail());

        Map<String, Boolean> scheme = null;
        try {
            scheme = ((MemberNotification) query.getSingleResult()).getScheme();
        } catch (NoResultException nre) {
            MemberNotification conf = new MemberNotificationImpl(member);
            em.persist(conf);
            scheme = conf.getScheme();
        }

        return scheme;

    }

    @Override
    public void setNotificationSchemeFor(Member member, Map<String, Boolean> scheme) {

        String queryStr = "from " + MemberNotificationImpl.class.getSimpleName()
                + " l where l.member.email =:email";
        Query query = createQuery(queryStr);
        query.setParameter("email", member.getEmail());

        MemberNotification notificationScheme = null;
        try {
            notificationScheme = (MemberNotification) query.getSingleResult();
        } catch (NoResultException nre) {
            notificationScheme = new MemberNotificationImpl(member);
            em.persist(notificationScheme);
        }

        Map<String, Boolean> current = notificationScheme.getScheme();
        for (Map.Entry<String, Boolean> entry : scheme.entrySet()) {
            current.put(entry.getKey(), entry.getValue());
        }
        notificationScheme.setScheme(current);

        log.debug("Notification scheme for member=" + member.getEmail() + " has been updated");

    }

    @Override
    public void sendEmail(Member member, Map<String, String> params) throws CoreException {

        final String emailsStr = params.get("emails");
        String[] emails = null;
        if (emailsStr != null) {
            emails = params.get("emails").split(",");
        }

        String format = params.get("format");
        if (format == null) {
            format = "text/html";
        }
        Message message = new MimeMessage(mailer);

        final String encodingOptions = format + "; charset=UTF-8";
        try {
            message.setHeader("Content-Type", encodingOptions);

            String from = params.get("from");
            if (from == null || from.equals("")) {
                message.setFrom(new InternetAddress(CoreConstants.SOFUN_MAIL_FROM));
            } else {
                message.setFrom(new InternetAddress(from));
            }

            InternetAddress to[] = null;
            if (emails == null) {
                to = new InternetAddress[1];
                to[0] = new InternetAddress(member.getEmail());
            } else {
                to = new InternetAddress[emails.length];
                for (int i = 0; i < emails.length; i++) {
                    to[i] = new InternetAddress(emails[i]);
                }
            }

            message.setRecipients(Message.RecipientType.TO, to);
            message.setSubject(params.get("subject"));

            String body = params.get("body");
            if (body != null) {
                body = body.replaceAll("(\\r|\\n)", "<p/>");
            }

            VelocityEngine ve = null;
            try {
                ve = getVelocityEngine();
            } catch (Exception e) {
                throw new CoreException(e.getMessage());
            }

            Template t = ve.getTemplate(params.get("templateId"));
            StringWriter writer = new StringWriter();

            VelocityContext context = new VelocityContext();

            // Add Member in velocity context.
            context.put("member", member);
            context.put("body", body);

            // Add all incoming params in velocity context.
            for (Map.Entry<String, String> entry : params.entrySet()) {
                context.put(entry.getKey(), entry.getValue());
            }

            t.merge(context, writer);

            message.setContent(writer.toString(), encodingOptions);
            Transport.send(message);
            String logEmails;
            if (emails != null) {
                logEmails = emailsStr;
            } else {
                logEmails = member.getEmail();
            }
            log.info("Sending an email to=" + logEmails);
        } catch (MessagingException e) {
            log.error("Failed to send an email. See error below.");
            throw new CoreException(e.getMessage());
        }

    }

    /**
     * Load all templates at post construction time.
     * 
     * <p/>
     * 
     * All templates will then be available in memory whenever needed.
     * 
     * @throws Exception
     */
    @PostConstruct
    protected void loadNotificationTemplates() throws Exception {

        log.debug("Loading email templates in memory...");
        InputStreamReader utf8Reader = null;
        InputStream raw = null;
        try {

            log.debug("Loading email templates in memory...");
            Properties p = new Properties();

            // Get the templates properties file referencing all available
            // templates.
            raw = getClass().getResourceAsStream(TEMPLATE_PROPERTIES);
            utf8Reader = new InputStreamReader(raw, "UTF-8");
            if (utf8Reader != null) {
                p.load(raw);
            }

            // Initialize VE engine.
            getVelocityEngine();

            // Initialize the string resource loader
            templateRepository = StringResourceLoader.getRepository();

            // Load each templates for each locale.
            for (Object entry : p.keySet()) {

                final String tid = (String) entry;
                final String tname = p.getProperty(tid);

                for (String locale : LOCALES) {

                    final String templatePath = "/mail-templates/" + locale + "/" + tname;
                    final String templateId = tid + "_" + locale;

                    String template;
                    try {
                        template = getTemplateFromJar(templatePath);
                    } catch (Exception e) {
                        continue;
                    }

                    if (template != null) {
                        templateRepository.putStringResource(templateId, template);
                        log.debug("Loading template with path=" + templatePath);
                    } else {
                        log.error("Cannot find template with path=" + templatePath);
                    }

                }

            }

        } finally {
            if (utf8Reader != null) {
                utf8Reader.close();
            }
            if (raw != null) {
                raw.close();
            }
        }

    }

    /**
     * Gets a mail template content from within the JAR file.
     * 
     * @param templatePath: relative path to the template within the JAR file.
     *        For instance, "/mail-templates/fr/betkup-welcome.vm".
     * @return the content of the template as a {@link String}
     * @throws Exception
     */
    private String getTemplateFromJar(String templatePath) throws Exception {
        InputStream inStream = null;
        InputStreamReader streamReader = null;
        BufferedReader bufferedReader = null;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            inStream = getClass().getResourceAsStream(templatePath);
            streamReader = new InputStreamReader(inStream, "UTF-8");
            bufferedReader = new BufferedReader(streamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
        } finally {
            if (inStream != null) {
                inStream.close();
            }
            if (streamReader != null) {
                streamReader.close();
            }
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }
        return stringBuilder.toString();
    }

    /**
     * Initializes and return the {@link VelocityEngine}.
     * 
     * <p/>
     * 
     * Initializes the velocity engine with properties. We should specify the
     * resource loader as string and the class for string.resource.loader in
     * properties
     * 
     * 
     * @param engine: a {@link Velocity} engine.
     * @return a {@link Velocity} engine.
     * @throws Exception
     */
    private VelocityEngine getVelocityEngine() throws Exception {

        if (velocityEngine == null) {

            Properties p = new Properties();
            p.setProperty("input.encoding", "UTF-8");
            p.setProperty("output.encoding", "UTF-8");

            p.setProperty("resource.loader", "string");
            p.setProperty("string.resource.loader.class",
                    "org.apache.velocity.runtime.resource.loader.StringResourceLoader");

            velocityEngine = new VelocityEngine();
            velocityEngine.init(p);

        }

        return velocityEngine;

    }

}