001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.mail;
019    
020    import java.io.PrintStream;
021    import java.io.PrintWriter;
022    
023    /**
024     * Exception thrown when a checked error occurs in commons-email.
025     * <p>
026     * Supports nesting, emulating JDK 1.4 behavior if necessary.
027     * <p>
028     * Adapted from FunctorException in Commons Collections.
029     *
030     * @author jakarta-commons
031     * @since 1.0
032     * @version $Id: EmailException.java 510812 2007-02-23 04:32:22Z dion $
033     */
034    public class EmailException
035            extends Exception
036    {
037        /** Serializable version identifier */
038        static final long serialVersionUID = 5550674499282474616L;
039    
040        /**
041         * Does JDK support nested exceptions?
042         */
043        private static final boolean JDK_SUPPORTS_NESTED;
044    
045        static
046        {
047            boolean flag = false;
048    
049            try
050            {
051                Throwable.class.getDeclaredMethod("getCause", new Class[0]);
052                flag = true;
053            }
054            catch (NoSuchMethodException ex)
055            {
056                flag = false;
057            }
058    
059            JDK_SUPPORTS_NESTED = flag;
060        }
061    
062        /**
063         * Root cause of the exception
064         */
065        private final Throwable rootCause;
066    
067        /**
068         * Constructs a new <code>EmailException</code> with no
069         * detail message.
070         */
071        public EmailException()
072        {
073            super();
074            this.rootCause = null;
075        }
076    
077        /**
078         * Constructs a new <code>EmailException</code> with specified
079         * detail message.
080         *
081         * @param msg  the error message.
082         */
083        public EmailException(String msg)
084        {
085            super(msg);
086            this.rootCause = null;
087        }
088    
089        /**
090         * Constructs a new <code>EmailException</code> with specified
091         * nested <code>Throwable</code> root cause.
092         *
093         * @param rootCause  the exception or error that caused this exception
094         *                   to be thrown.
095         */
096        public EmailException(Throwable rootCause)
097        {
098            super((rootCause == null) ? null : rootCause.getMessage());
099            this.rootCause = rootCause;
100        }
101    
102        /**
103         * Constructs a new <code>EmailException</code> with specified
104         * detail message and nested <code>Throwable</code> root cause.
105         *
106         * @param msg  the error message.
107         * @param rootCause  the exception or error that caused this exception
108         *                   to be thrown.
109         */
110        public EmailException(String msg, Throwable rootCause)
111        {
112            super(msg);
113            this.rootCause = rootCause;
114        }
115    
116        /**
117         * Gets the cause of this throwable.
118         *
119         * @return  the cause of this throwable, or <code>null</code>
120         */
121        public Throwable getCause()
122        {
123            return rootCause;
124        }
125    
126        /**
127         * Prints the stack trace of this exception to the standard error stream.
128         */
129        public void printStackTrace()
130        {
131            printStackTrace(System.err);
132        }
133    
134        /**
135         * Prints the stack trace of this exception to the specified stream.
136         *
137         * @param out  the <code>PrintStream</code> to use for output
138         */
139        public void printStackTrace(PrintStream out)
140        {
141            synchronized (out)
142            {
143                PrintWriter pw = new PrintWriter(out, false);
144                printStackTrace(pw);
145    
146                // Flush the PrintWriter before it's GC'ed.
147                pw.flush();
148            }
149        }
150    
151        /**
152         * Prints the stack trace of this exception to the specified writer.
153         *
154         * @param out  the <code>PrintWriter</code> to use for output
155         */
156        public void printStackTrace(PrintWriter out)
157        {
158            synchronized (out)
159            {
160                super.printStackTrace(out);
161    
162                if (!JDK_SUPPORTS_NESTED && (rootCause != null))
163                {
164                    out.print("Caused by: ");
165                    rootCause.printStackTrace(out);
166                }
167            }
168        }
169    }