Package org.apache.cocoon.mail

Source Code of org.apache.cocoon.mail.MailMessageSender

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.mail;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;

import org.apache.avalon.framework.CascadingRuntimeException;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;

import org.apache.cocoon.mail.datasource.AbstractDataSource;
import org.apache.cocoon.mail.datasource.FilePartDataSource;
import org.apache.cocoon.mail.datasource.InputStreamDataSource;
import org.apache.cocoon.mail.datasource.SourceDataSource;
import org.apache.cocoon.servlet.multipart.Part;
import org.apache.cocoon.util.AbstractLogEnabled;

/**
* A helper class used by the {@link org.apache.cocoon.acting.Sendmail}
* and the <code>sendmail.xsl</code> logicsheet for sending an email message.
*
* <h3>Configuration</h3>
* <table><tbody>
* <tr><th>smtp-host</th><td>SMTP server to use sending mail.</td><td>opt</td><td>String</td><td><code>localhost</code></td></tr>
* <tr><th>smtp-user</th><td>User name for authentication</td><td>opt</td><td>String</td></tr>
* <tr><th>smtp-password</th><td>Password for authentication</td><td>opt</td><td>String</td></tr>
* </tbody></table>
*
* @since 2.1
* @version $Id: MailMessageSender.java 587761 2007-10-24 03:08:05Z vgritsenko $
*/
public class MailMessageSender extends AbstractLogEnabled
                               implements MailSender, Configurable, Serviceable,
                                          Initializable {

    private ServiceManager manager;

    private Session session;

    private String smtpHost;
    private String smtpUser;
    private String smtpPswd;

    private String from;
    private String to;
    private String replyTo;
    private String cc;
    private String bcc;
    private String subject;
    private String subjectCharset;

    private Attachment body;
    private String bodyType;
    private String bodySrcType;
    private List attachments;

    private Exception exception;


    /**
     * Check string for null, empty, and "null".
     * @param str
     * @return true if str is null, empty string, or equals "null"
     */
    private boolean isNullOrEmpty(String str) {
        return str == null || "".equals(str) || "null".equals(str);
    }

    /**
     * Helper class for attachment data.
     */
    private class Attachment {
        private Object obj;
        private String type;
        private String name;
        protected boolean isURL;

        /**
         * Create a new attachment object encapsulating obj.
         * @param obj attachment
         */
        public Attachment(Object obj) {
            this(obj, null, null);
        }

        /**
         * Create a new attachment object encapsulating obj
         * @param obj attachment
         * @param type override mime type
         * @param name override attachment name
         */
        public Attachment(Object obj, String type, String name) {
            this(obj, type, name, false);
        }

        /**
         * Create a new attachment object encapsulating obj
         * @param obj attachment
         * @param type override mime type
         * @param name override attachment name
         * @param isURI obj is an instance of String and contains a URL
         */
        public Attachment(Object obj, String type, String name, boolean isURI) {
            this.obj = obj;
            this.type = type;
            this.name = name;
            this.isURL = isURI;

            if (isNullOrEmpty(this.type)) {
                this.type = null;
            }

            if (isNullOrEmpty(this.name)) {
                this.name = null;
            }
        }

        /**
         * Is the encapsulated object a URL?
         * @return true if URL
         */
        public boolean isURL() {
            return this.isURL;
        }

        /**
         * Is the encapsulated object a text?
         * @return true if text (String object)
         */
        public boolean isText() {
            return !isURL() && this.obj instanceof String;
        }

        /**
         * Return attachment name.
         */
        public String getName() {
            return this.name;
        }

        /**
         * Return attachment type.
         */
        public String getType() {
            return this.type;
        }

        /**
         * Returns encapsulated object
         */
        public Object getObject() {
            return this.obj;
        }

        public String getText() {
            return (String) this.obj;
        }

        public DataSource getDataSource(SourceResolver resolver, List sources)
        throws IOException, MessagingException {
            AbstractDataSource ds = null;

            if (isURL) {
                String url = (String) getObject();
                Source src = resolver.resolveURI(url);
                sources.add(src);
                if (src.exists()) {
                    ds = new SourceDataSource(src, getType(), getName());
                }
            } else if (getObject() instanceof Part) {
                Part part = (Part) getObject();
                ds = new FilePartDataSource(part, getType(), getName());
            } else if (getObject() instanceof InputStream) {
                InputStream in = (InputStream) getObject();
                ds = new InputStreamDataSource(in, getType(), getName());
            } else if (getObject() instanceof byte[]) {
                byte[] data = (byte[]) getObject();
                ds = new InputStreamDataSource(data, getType(), getName());
            } else {
                // TODO: other classes?
                throw new MessagingException("Not yet supported: " + getObject());
            }

            return ds;
        }

        public void setContentTo(SourceResolver resolver, List sources, MimePart part)
        throws IOException, MessagingException {
            if (isText()) {
                // Set text
                if (type != null) {
                    part.setContent(getText(), type);
                } else {
                    // Let JavaMail decide on character encoding.
                    part.setText(getText());
                }
                if (name != null) {
                    part.setFileName(name);
                }
            } else {
                // Set data
                DataSource ds = getDataSource(resolver, sources);
                part.setDataHandler(new DataHandler(ds));
                String name = ds.getName();
                if (name != null) {
                    part.setFileName(name);
                }
            }
        }

        public MimeBodyPart getBodyPart(SourceResolver resolver, List sources)
        throws IOException, MessagingException {
            MimeBodyPart part = new MimeBodyPart();
            setContentTo(resolver, sources, part);
            return part;
        }
    }

    private class Body extends Attachment {
        public Body(Object obj) {
            super(obj);
        }

        public Body(Object obj, String type) {
            super(obj, type, null);
        }

        public Body(Object obj, String type, boolean isURI) {
            super(obj, type, null, isURI);
        }

        // Override to set name to null: body can not have name.
        public DataSource getDataSource(SourceResolver resolver, List sources)
        throws IOException, MessagingException {
            AbstractDataSource ds = (AbstractDataSource) super.getDataSource(resolver, sources);
            ds.setName(null);
            return ds;
        }
    }


    public MailMessageSender() {
    }

    /**
     * Creates a new instance of MailMessageSender.
     * Keep constructor for backwards compatibility.
     *
     * @param smtpHost The host name or ip-address of a host to accept
     *                 the email for delivery.
     * @deprecated Since 2.1.5. Please use {@link MailSender} component instead.
     */
    public MailMessageSender(String smtpHost) {
        smtpHost = smtpHost.trim();
        setSmtpHost(smtpHost);
        initialize();
    }

    public void service(ServiceManager manager) {
        this.manager = manager;
    }

    public void configure(Configuration config) throws ConfigurationException {
        this.smtpHost = config.getChild("smtp-host").getValue(null);
        this.smtpUser = config.getChild("smtp-user").getValue(null);
        this.smtpPswd = config.getChild("smtp-password").getValue(null);
    }

    public void initialize() {
        initSession();
        this.attachments = new ArrayList();
    }

    private void initSession() {
        Properties properties = new Properties();
        if (smtpHost == null || smtpHost.equals("") || smtpHost.equals("null")) {
            properties.put("mail.smtp.host", "127.0.0.1");
        } else {
            properties.put("mail.smtp.host", smtpHost);
        }

        if (smtpUser == null || smtpUser.equals("") || smtpUser.equals("null")) {
            this.session = Session.getInstance(properties);
        } else {
            properties.put("mail.smtp.auth", "true");
            this.session = Session.getInstance(properties, new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(smtpUser, smtpPswd);
                }
            });
        }
    }

    /* (non-Javadoc)
     * @see org.apache.cocoon.mail.MailSender#setSmtpHost(java.lang.String)
     */
    public void setSmtpHost(String hostname) {
        this.smtpHost = hostname;
        initSession();
    }

    public void setSmtpHost(String hostname, String username, String password) {
        this.smtpUser = username;
        this.smtpPswd = password;
        setSmtpHost(hostname);
    }

    /**
     * Assemble the message from the defined fields and send it.
     *
     * @throws AddressException when problems with email addresses are found
     * @throws MessagingException when message could not be send.
     */
    public void send() throws AddressException, MessagingException {
        SourceResolver resolver = null;
        try {
            resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
            doSend(resolver);
        } catch (ServiceException se) {
            throw new CascadingRuntimeException("Cannot get Source Resolver to send mail", se);
        } finally {
            this.manager.release(resolver);
        }
    }

    /**
     * Assemble the message from the defined fields and send it.
     *
     * @throws AddressException when problems with email addresses are found
     * @throws MessagingException when message could not be send.
     * @deprecated Since 2.1.5. Use {@link #send()} which doesn't require passing the source resolver
     */
    public void send(org.apache.cocoon.environment.SourceResolver resolver)
    throws AddressException, MessagingException {
        // resolver is automatically down-casted
        doSend(resolver);
    }

    private void doSend(SourceResolver resolver)
    throws AddressException, MessagingException {

        final MimeMessage message = new MimeMessage(this.session);

        if (this.from == null) {
            throw new AddressException("No from address");
        } else {
            try {
                message.setFrom(new InternetAddress(this.from));
            } catch (AddressException e) {
                throw new AddressException("Invalid from address: " + this.from + ": " +
                                           e.getMessage());
            }
        }

        if (this.to == null) {
            throw new AddressException("no to address");
        } else {
            try {
                message.setRecipients(RecipientType.TO,
                                      InternetAddress.parse(this.to));
            } catch (AddressException e) {
                throw new AddressException("Invalid to address: " + this.to + ": " +
                                           e.getMessage());
            }
        }

        if (this.replyTo != null) {
            try {
                message.setReplyTo(InternetAddress.parse(this.replyTo));
            } catch (AddressException e) {
                throw new AddressException("Invalid replyTo address: " + this.replyTo + ": " +
                                           e.getMessage());
            }
        }

        if (this.cc != null) {
            try {
                message.setRecipients(RecipientType.CC,
                                      InternetAddress.parse(this.cc));
            } catch (AddressException e) {
                throw new AddressException("Invalid cc address: " + this.cc + ": " +
                                           e.getMessage());
            }
        }

        if (this.bcc != null) {
            try {
                message.setRecipients(RecipientType.BCC,
                                      InternetAddress.parse(this.bcc));
            } catch (AddressException e) {
                throw new AddressException("Invalid bcc address: " + this.bcc + ": " +
                                           e.getMessage());
            }
        }

        if (this.subject != null) {
            if (this.subjectCharset == null) {
                message.setSubject(this.subject);
            } else {
                message.setSubject(this.subject, this.subjectCharset);
            }
        }

        message.setSentDate(new Date());

        Attachment a = null;
        final List sources = new ArrayList();
        try {
            if (this.attachments.isEmpty()) {
                // Message consists of single part
                if (this.body != null) {
                    a = this.body;
                    a.setContentTo(resolver, sources, message);
                }
            } else {
                // Message consists of multiple parts
                Multipart multipart = new MimeMultipart();
                message.setContent(multipart);

                // Body part
                if (this.body != null) {
                    a = this.body;
                    multipart.addBodyPart(a.getBodyPart(resolver, sources));
                }

                // Attachment parts
                for (Iterator i = this.attachments.iterator(); i.hasNext();) {
                    a = (Attachment) i.next();
                    multipart.addBodyPart(a.getBodyPart(resolver, sources));
                }
            }

            message.saveChanges();
            Transport.send(message);
        } catch (MalformedURLException e) {
            throw new MessagingException("Malformed attachment URL: " +
                                         a.getObject() + " error " + e.getMessage());
        } catch (IOException e) {
            throw new MessagingException("IOException accessing attachment URL: " +
                                         a.getObject() + " error " + e.getMessage());
        } finally {
            for (Iterator j = sources.iterator(); j.hasNext();) {
                resolver.release((Source) j.next());
            }
        }
    }

    /**
     * Invokes the {@link #send()} method but catches any exception thrown. This
     * method is intended to be used from the sendmail logicsheet.
     *
     * @return true when successful
     */
    public boolean sendIt() {
        this.exception = null;
        try {
            send();
        } catch (Exception e) {
            this.exception = e;
        }
        return exception == null;
    }

    /**
     * Invokes the {@link #send(org.apache.cocoon.environment.SourceResolver)}
     * method but catches any exception thrown. This
     * method is intended to be used from the sendmail logicsheet.
     *
     * @return true when successful
     * @deprecated Since 2.1.5. Use {@link #sendIt()} which doesn't require passing the source resolver
     */
    public boolean sendIt(org.apache.cocoon.environment.SourceResolver resolver) {
        this.exception = null;
        try {
            send(resolver);
        } catch (Exception e) {
            this.exception = e;
        }
        return exception == null;
    }

    /**
     * Accesses any Exception caught by
     * {@link #sendIt(org.apache.cocoon.environment.SourceResolver)}.
     *
     * @return AddressException or MessagingException
     */
    public Exception getException() {
        return this.exception;
    }


    /**
     * Set the <code>from</code> address of the message.
     *
     * @param from The address the message appears to be from.
     */
    public void setFrom(String from) {
        if (!isNullOrEmpty(from)) {
            this.from = from.trim();
        }
    }

    /**
     * Sets the destination address(es) for the message. The address
     * is in the format, that
     * {@link javax.mail.internet.InternetAddress#parse(String)} can handle
     * (one or more email addresses separated by a commas).
     *
     * @param to the destination address(es)
     * @see javax.mail.internet.InternetAddress#parse(String)
     */
    public void setTo(String to) {
        if (!isNullOrEmpty(to)) {
            this.to = to.trim();
        }
    }

    /**
     * Sets the reply-to address(es) for the message. The address
     * is in the format, that
     * {@link javax.mail.internet.InternetAddress#parse(String)} can handle
     * (one or more email addresses separated by a commas).
     *
     * @param replyTo the address(es) that replies should be sent to
     * @see javax.mail.internet.InternetAddress#parse(String)
     */
    public void setReplyTo(String replyTo) {
        if (!isNullOrEmpty(replyTo)) {
            this.replyTo = replyTo.trim();
        }
    }

    /**
     * Sets the address(es), which should receive a carbon copy of the
     * message. The address is in the format, that
     * {@link javax.mail.internet.InternetAddress#parse(String)} can handle
     * (one or more email addresses separated by a commas).
     *
     * @param cc the address(es), which should receive a carbon copy.
     * @see javax.mail.internet.InternetAddress#parse(String)
     */
    public void setCc(String cc) {
        if (!isNullOrEmpty(cc)) {
            this.cc = cc.trim();
        }
    }

    /**
     * Sets the address(es), which should receive a black carbon copy of
     * the message. The address is in the format, that
     * {@link javax.mail.internet.InternetAddress#parse(String)} can handle
     * (one or more email addresses separated by a commas).
     *
     * @param bcc the address(es), which should receive a black carbon copy.
     * @see javax.mail.internet.InternetAddress#parse(String)
     */
    public void setBcc(String bcc) {
        if (!isNullOrEmpty(bcc)) {
            this.bcc = bcc.trim();
        }
    }

    /**
     * Sets the subject line of the message.
     *
     * @param subject the subject line of the message
     */
    public void setSubject(String subject) {
        if (!isNullOrEmpty(subject)) {
            this.subject = subject;
        }
    }

    /**
     * Sets the subject line of the message.
     *
     * @param subject the subject line of the message
     * @param charset the character set to be used for encoding the subject
     */
    public void setSubject(String subject, String charset) {
        setSubject(subject);
        if (!isNullOrEmpty(charset)) {
            this.subjectCharset = charset;
        }
    }

    /**
     * Sets the character set for encoding the message. This has no effect,
     * if any attachments are send in the message.
     *
     * @param charset the character set to be used for enbcoding the message
     */
    public void setCharset(String charset) {
        if (!isNullOrEmpty(charset)) {
            this.bodyType = "text/plain; charset=" + charset.trim();
            if (this.body != null && this.body.isText() && this.body.type == null) {
                this.body.type = this.bodyType;
            }
        }
    }

    /**
     * Sets the body text of the email message.
     * If both a text body and a body read from a source are set,
     * only the latter will be used.
     *
     * @param body The body text of the email message
     * @deprecated Since 2.1.10. Use {@link #setBody(Object)}
     */
    public void setBody(String body) {
        if (!isNullOrEmpty(body)) {
            setBody(body, bodyType);
        }
    }

    /**
     * Sets the body source URL of the email message.
     * If both a text body and a body read from a source are set,
     * only the latter will be used.
     *
     * @param src The body source URL of the email message
     * @deprecated Since 2.1.10. Use {@link #setBodyURL(String)}
     */
    public void setBodyFromSrc(String src) {
        if (!isNullOrEmpty(src)) {
           setBodyURL(src, bodySrcType);
        }
    }

    /**
     * Sets the optional body source Mime Type of the email message.
     *
     * @param srcMimeType The optional body source Mime Type of the email message
     * @deprecated Since 2.1.10. Use {@link #setBodyURL(String, String)}
     */
    public void setBodyFromSrcMimeType(String srcMimeType) {
        if (!isNullOrEmpty(srcMimeType)) {
            this.bodySrcType = srcMimeType;
            // Pass into this.body if it was set.
            if (this.body != null && this.body.isURL() && this.body.type == null) {
                this.body.type = srcMimeType;
            }
        }
    }

    /**
     * Sets the body content of the email message.
     *
     * <p>The body can be any of: {@link org.apache.excalibur.source.Source},
     * {@link org.apache.cocoon.servlet.multipart.Part}, {@link java.io.InputStream},
     * <code>byte[]</code>, {@link String}, or a subclass.
     *
     * @param body The body text of the email message
     */
    public void setBody(Object body) {
        setBody(body, null);
    }

    /**
     * Sets the body content of the email message.
     *
     * <p>The body can be any of: {@link org.apache.excalibur.source.Source},
     * {@link org.apache.cocoon.servlet.multipart.Part}, {@link java.io.InputStream},
     * <code>byte[]</code>, {@link String}, or a subclass.
     *
     * @param body The body text of the email message
     * @param type mime type (optional)
     */
    public void setBody(Object body, String type) {
        if (body != null) {
            this.body = new Body(body, type);
        }
    }

    /**
     * Sets the body content of the email message.
     *
     * @param url URL to use as message body
     * @see org.apache.excalibur.source.Source
     */
    public void setBodyURL(String url) {
        setBodyURL(url, null);
    }

    /**
     * Sets the body content of the email message.
     *
     * @param url URL to use as message body
     * @param type mime type (optional)
     * @see org.apache.excalibur.source.Source
     */
    public void setBodyURL(String url, String type) {
        if (url != null) {
            this.body = new Body(url, type, true);
        }
    }

    /**
     * Add an attachement to the message to be send.
     *
     * <p>The attachment can be any of: {@link org.apache.excalibur.source.Source},
     * {@link org.apache.cocoon.servlet.multipart.Part}, {@link java.io.InputStream},
     * <code>byte[]</code>, {@link String}, or a subclass.
     *
     * @param attachment to be send with the message
     */
    public void addAttachment(Object attachment) {
        if (attachment != null) {
            attachments.add(new Attachment(attachment));
        }
    }

    /**
     * Add an attachement to the message to be send.
     *
     * <p>The attachment can be any of: {@link org.apache.excalibur.source.Source},
     * {@link org.apache.cocoon.servlet.multipart.Part}, {@link java.io.InputStream},
     * <code>byte[]</code>, {@link String}, or a subclass.
     *
     * @param attachment to be send with the message
     * @param type mime type (optional)
     * @param name attachment name (optional)
     */
    public void addAttachment(Object attachment, String type, String name) {
        if (attachment != null) {
            attachments.add(new Attachment(attachment, type, name));
        }
    }

    /**
     * Add an attachement to the message to be send.
     *
     * @param url URL to attach to the message
     * @see org.apache.excalibur.source.Source
     */
    public void addAttachmentURL(String url) {
        if (url != null) {
            attachments.add(new Attachment(url, null, null, true));
        }
    }

    /**
     * Add an attachement to the message to be send.
     *
     * @param url URL to attach to the message
     * @param type mime type (optional)
     * @param name attachment name (optional)
     * @see org.apache.excalibur.source.Source
     */
    public void addAttachmentURL(String url, String type, String name) {
        if (url != null) {
            attachments.add(new Attachment(url, type, name, true));
        }
    }
}
TOP

Related Classes of org.apache.cocoon.mail.MailMessageSender

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.