FileDocCategorySizeDatePackage
AbstractNotify.javaAPI DocApache James 2.3.111081Fri Jan 12 12:56:28 GMT 2007org.apache.james.transport.mailets

AbstractNotify.java

/****************************************************************
 * 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.james.transport.mailets;

import org.apache.mailet.RFC2822Headers;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;

import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;

/**
 * <P>Abstract mailet providing configurable notification services.<BR>
 * This mailet can be subclassed to make authoring notification mailets simple.<BR>
 * <P>Provides the following functionalities to all notification subclasses:</P>
 * <UL>
 * <LI>A common notification message layout.</LI>
 * <LI>A sender of the notification message can optionally be specified.
 * If one is not specified, the postmaster's address will be used.</LI>
 * <LI>A notice text can be specified, and in such case will be inserted into the 
 * notification inline text.</LI>
 * <LI>If the notified message has an "error message" set, it will be inserted into the 
 * notification inline text. If the <CODE>attachStackTrace</CODE> init parameter
 * is set to true, such error message will be attached to the notification message.</LI>
 * <LI>The notified messages are attached in their entirety (headers and
 * content) and the resulting MIME part type is "message/rfc822".</LI>
 * <LI>Supports by default the <CODE>passThrough</CODE> init parameter (true if missing).</LI>
 * </UL>
 *
 * <P>Sample configuration common to all notification mailet subclasses:</P>
 * <PRE><CODE>
 * <mailet match="All" class="<I>a notification mailet</I>">
 *   <sender><I>an address or postmaster or sender or unaltered, default=postmaster</I></sender>
 *   <attachError><I>true or false, default=false</I></attachError>
 *   <message><I>notice attached to the original message text (optional)</I></message>
 *   <prefix><I>optional subject prefix prepended to the original message</I></prefix>
 *   <inline><I>see {@link Redirect}, default=none</I></inline>
 *   <attachment><I>see {@link Redirect}, default=message</I></attachment>
 *   <passThrough><I>true or false, default=true</I></passThrough>
 *   <fakeDomainCheck><I>true or false, default=true</I></fakeDomainCheck>
 *   <debug><I>true or false, default=false</I></debug>
 * </mailet>
 * </CODE></PRE>
 * <P><I>notice</I> and <I>senderAddress</I> can be used instead of
 * <I>message</I> and <I>sender</I>; such names are kept for backward compatibility.</P>
 *
 * @version CVS $Revision: 494012 $ $Date: 2007-01-08 11:23:58 +0100 (Mo, 08 Jan 2007) $
 * @since 2.2.0
 */
public abstract class AbstractNotify extends AbstractRedirect {

    /* ******************************************************************** */
    /* ****************** Begin of getX and setX methods ****************** */
    /* ******************************************************************** */

    /**
     * @return the <CODE>passThrough</CODE> init parameter, or true if missing
     */
    protected boolean getPassThrough() throws MessagingException {
        return new Boolean(getInitParameter("passThrough","true")).booleanValue();
    }

    /**
     * @return the <CODE>inline</CODE> init parameter, or <CODE>NONE</CODE> if missing
     */
    protected int getInLineType() throws MessagingException {
        return getTypeCode(getInitParameter("inline","none"));
    }

    /**
     * @return the <CODE>attachment</CODE> init parameter, or <CODE>MESSAGE</CODE> if missing
     */
    protected int getAttachmentType() throws MessagingException {
        return getTypeCode(getInitParameter("attachment","message"));
    }

    /**
     * @return the <CODE>notice</CODE> init parameter,
     * or the <CODE>message</CODE> init parameter if missing,
     * or a default string if both are missing
     */
    protected String getMessage() {
        return getInitParameter("notice",
                getInitParameter("message",
                "We were unable to deliver the attached message because of an error in the mail server."));
    }

    /**
     * @return the full message to append, built from the Mail object
     */
    protected String getMessage(Mail originalMail) throws MessagingException {
        MimeMessage message = originalMail.getMessage();
        StringWriter sout = new StringWriter();
        PrintWriter out = new PrintWriter(sout, true);

        // First add the "local" notice
        // (either from conf or generic error message)
        out.println(getMessage());
        // And then the message from other mailets
        if (originalMail.getErrorMessage() != null) {
            out.println();
            out.println("Error message below:");
            out.println(originalMail.getErrorMessage());
        }
        out.println();
        out.println("Message details:");

        if (message.getSubject() != null) {
            out.println("  Subject: " + message.getSubject());
        }
        if (message.getSentDate() != null) {
            out.println("  Sent date: " + message.getSentDate());
        }
        out.println("  MAIL FROM: " + originalMail.getSender());
        Iterator rcptTo = originalMail.getRecipients().iterator();
        out.println("  RCPT TO: " + rcptTo.next());
        while (rcptTo.hasNext()) {
            out.println("           " + rcptTo.next());
        }
        String[] addresses = null;
        addresses = message.getHeader(RFC2822Headers.FROM);
        if (addresses != null) {
            out.print("  From: ");
            for (int i = 0; i < addresses.length; i++) {
                out.print(addresses[i] + " ");
            }
            out.println();
        }
        addresses = message.getHeader(RFC2822Headers.TO);
        if (addresses != null) {
            out.print("  To: ");
            for (int i = 0; i < addresses.length; i++) {
                out.print(addresses[i] + " ");
            }
            out.println();
        }
        addresses = message.getHeader(RFC2822Headers.CC);
        if (addresses != null) {
            out.print("  CC: ");
            for (int i = 0; i < addresses.length; i++) {
                out.print(addresses[i] + " ");
            }
            out.println();
        }
        out.println("  Size (in bytes): " + message.getSize());
        if (message.getLineCount() >= 0) {
            out.println("  Number of lines: " + message.getLineCount());
        }

        return sout.toString();
    }

    // All subclasses of AbstractNotify are expected to establish their own recipients
    abstract protected Collection getRecipients() throws MessagingException;

    /**
     * @return null
     */
    protected InternetAddress[] getTo() throws MessagingException {
        return null;
    }

    /**
     * @return <CODE>SpecialAddress.NULL</CODE>, that will remove the "ReplyTo:" header
     */
    protected MailAddress getReplyTo() throws MessagingException {
        return SpecialAddress.NULL;
    }

    /**
     * @return {@link AbstractRedirect#getSender(Mail)}, meaning the new requested sender if any
     */
    protected MailAddress getReversePath(Mail originalMail) throws MessagingException {
        return getSender(originalMail);
    }

    /**
     * @return the value of the <CODE>sendingAddress</CODE> init parameter,
     * or the value of the <CODE>sender</CODE> init parameter if missing,
     * or the postmaster address if both are missing
     * @return the <CODE>sendingAddress</CODE> init parameter
     * or the <CODE>sender</CODE> init parameter
     * or the postmaster address if both are missing;
     * possible special addresses returned are
     * <CODE>SpecialAddress.SENDER</CODE>
     * and <CODE>SpecialAddress.UNALTERED</CODE>
     */
    protected MailAddress getSender() throws MessagingException {
        String addressString = getInitParameter("sendingAddress",getInitParameter("sender"));
        
        if (addressString == null) {
            return getMailetContext().getPostmaster();
        }
        
        MailAddress specialAddress = getSpecialAddress(addressString,
                                        new String[] {"postmaster", "sender", "unaltered"});
        if (specialAddress != null) {
            return specialAddress;
        }

        try {
            return new MailAddress(addressString);
        } catch(Exception e) {
            throw new MessagingException("Exception thrown in getSender() parsing: " + addressString, e);
        }
    }

    /**
     * @return null
     */
    protected String getSubject() throws MessagingException {
        return null;
    }

    /**
     * @return the <CODE>prefix</CODE> init parameter or "Re:" if missing
     */
    protected String getSubjectPrefix() {
        return getInitParameter("prefix","Re:");
    }

    /**
     * Builds the subject of <I>newMail</I> appending the subject
     * of <I>originalMail</I> to <I>subjectPrefix</I>, but avoiding a duplicate.
     */
    protected void setSubjectPrefix(Mail newMail, String subjectPrefix, Mail originalMail) throws MessagingException {
        String subject = originalMail.getMessage().getSubject();
        if (subject == null) {
            subject = "";
        }
        if (subjectPrefix==null || subject.indexOf(subjectPrefix) == 0) {
            newMail.getMessage().setSubject(subject);
        } else {
            newMail.getMessage().setSubject(subjectPrefix + subject);
        }
    }

    /**
     * @return true
     */
    protected boolean isReply() {
        return true;
    }

    /* ******************************************************************** */
    /* ******************* End of getX and setX methods ******************* */
    /* ******************************************************************** */

}