001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bstefanescu
018 */
019package org.nuxeo.ecm.automation.core.mail;
020
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.IOException;
024import java.io.StringReader;
025import java.io.StringWriter;
026import java.io.Writer;
027import java.net.URL;
028import java.util.List;
029import java.util.Properties;
030import java.util.concurrent.ConcurrentHashMap;
031import java.util.concurrent.ConcurrentMap;
032
033import javax.activation.DataHandler;
034import javax.mail.MessagingException;
035import javax.mail.internet.MimeBodyPart;
036import javax.mail.internet.MimeMultipart;
037
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040import org.nuxeo.ecm.core.api.Blob;
041import org.nuxeo.ecm.platform.rendering.api.RenderingException;
042import org.nuxeo.ecm.platform.rendering.api.ResourceLocator;
043import org.nuxeo.ecm.platform.rendering.fm.FreemarkerEngine;
044import org.nuxeo.runtime.api.Framework;
045
046import freemarker.core.Environment;
047import freemarker.template.Template;
048import freemarker.template.TemplateException;
049
050/**
051 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
052 */
053public class Composer {
054
055    private static final Log log = LogFactory.getLog(Composer.class);
056
057    protected final FreemarkerEngine engine;
058
059    protected Mailer mailer;
060
061    // FIXME: don't put URLs in Maps, this is a serious performance issue.
062    protected final ConcurrentMap<String, URL> urls;
063
064    public Composer() {
065        this(null);
066    }
067
068    public Composer(Mailer mailer) {
069        urls = new ConcurrentHashMap<String, URL>();
070        if (mailer == null) {
071            this.mailer = createMailer();
072        } else {
073            this.mailer = mailer;
074        }
075        engine = new FreemarkerEngine();
076        engine.setResourceLocator(new ResourceLocator() {
077            @Override
078            public URL getResourceURL(String key) {
079                return urls.get(key);
080            }
081
082            @Override
083            public File getResourceFile(String key) {
084                return null;
085            }
086        });
087    }
088
089    protected Mailer createMailer() {
090        // first try the local configuration
091        org.nuxeo.common.Environment env = org.nuxeo.common.Environment.getDefault();
092        if (env != null) {
093            File file = new File(env.getConfig(), "mail.properties");
094            if (file.isFile()) {
095                Properties p = new Properties();
096                try {
097                    FileInputStream in = new FileInputStream(file);
098                    try {
099                        p.load(in);
100                        mailer = new Mailer(p);
101                    } finally {
102                        in.close();
103                    }
104                } catch (IOException e) {
105                    log.error("Failed to load mail properties", e);
106                }
107            }
108        }
109        // second try using JNDI
110        if (mailer == null) {
111            String name = Framework.getProperty("jndi.java.mail", "java:/Mail");
112            mailer = new Mailer(name);
113        }
114        return mailer;
115    }
116
117    public void registerTemplate(URL url) {
118        urls.put(url.toExternalForm(), url);
119    }
120
121    public void unregisterTemplate(URL url) {
122        urls.remove(url.toExternalForm());
123    }
124
125    public void unregisterAllTemplates() {
126        urls.clear();
127    }
128
129    public Mailer getMailer() {
130        return mailer;
131    }
132
133    public FreemarkerEngine getEngine() {
134        return engine;
135    }
136
137    public void render(String template, Object ctx, Writer writer) throws RenderingException {
138        engine.render(template, ctx, writer);
139    }
140
141    public void render(URL template, Object ctx, Writer writer) throws RenderingException {
142        String key = template.toExternalForm();
143        urls.putIfAbsent(key, template);
144        engine.render(key, ctx, writer);
145    }
146
147    public String render(URL template, Object ctx) throws RenderingException {
148        String key = template.toExternalForm();
149        urls.putIfAbsent(key, template);
150        StringWriter writer = new StringWriter();
151        engine.render(key, ctx, writer);
152        return writer.toString();
153    }
154
155    public String render(String templateContent, Object ctx) throws TemplateException, IOException {
156        StringReader reader = new StringReader(templateContent);
157        Template temp = new Template("@inline", reader, engine.getConfiguration(), "UTF-8");
158        StringWriter writer = new StringWriter();
159        Environment env = temp.createProcessingEnvironment(ctx, writer, engine.getObjectWrapper());
160        env.process();
161        return writer.toString();
162    }
163
164    public Mailer.Message newMessage() {
165        return mailer.newMessage();
166    }
167
168    public Mailer.Message newTextMessage(URL template, Object ctx) throws RenderingException, MessagingException {
169        Mailer.Message msg = mailer.newMessage();
170        msg.setText(render(template, ctx), "UTF-8");
171        return msg;
172    }
173
174    public Mailer.Message newTextMessage(String templateContent, Object ctx) throws RenderingException,
175            MessagingException, TemplateException, IOException {
176        Mailer.Message msg = mailer.newMessage();
177        msg.setText(render(templateContent, ctx), "UTF-8");
178        return msg;
179    }
180
181    public Mailer.Message newHtmlMessage(URL template, Object ctx) throws RenderingException, MessagingException {
182        Mailer.Message msg = mailer.newMessage();
183        msg.setContent(render(template, ctx), "text/html; charset=utf-8");
184        return msg;
185    }
186
187    public Mailer.Message newHtmlMessage(String templateContent, Object ctx) throws MessagingException,
188            TemplateException, IOException {
189        Mailer.Message msg = mailer.newMessage();
190        msg.setContent(render(templateContent, ctx), "text/html; charset=utf-8");
191        return msg;
192    }
193
194    public Mailer.Message newMixedMessage(String templateContent, Object ctx, String textType, List<Blob> attachments)
195            throws TemplateException, IOException, MessagingException {
196        if (textType == null) {
197            textType = "plain";
198        }
199        Mailer.Message msg = mailer.newMessage();
200        MimeMultipart mp = new MimeMultipart();
201        MimeBodyPart body = new MimeBodyPart();
202        String result = render(templateContent, ctx);
203        body.setText(result, "UTF-8", textType);
204        mp.addBodyPart(body);
205        for (Blob blob : attachments) {
206            MimeBodyPart a = new MimeBodyPart();
207            a.setDataHandler(new DataHandler(new BlobDataSource(blob)));
208            a.setFileName(blob.getFilename());
209            mp.addBodyPart(a);
210        }
211        msg.setContent(mp);
212        return msg;
213    }
214
215}