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    package org.apache.commons.collections;
018    
019    import java.io.PrintStream;
020    import java.io.PrintWriter;
021    
022    /**
023     * Runtime exception thrown from functors.
024     * If required, a root cause error can be wrapped within this one.
025     * 
026     * @since Commons Collections 3.0
027     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
028     *
029     * @author Stephen Colebourne
030     */
031    public class FunctorException extends RuntimeException {
032        
033        /**
034         * Does JDK support nested exceptions
035         */
036        private static final boolean JDK_SUPPORTS_NESTED;
037        
038        static {
039            boolean flag = false;
040            try {
041                Throwable.class.getDeclaredMethod("getCause", new Class[0]);
042                flag = true;
043            } catch (NoSuchMethodException ex) {
044                flag = false;
045            }
046            JDK_SUPPORTS_NESTED = flag;
047        }
048        
049        /**
050         * Root cause of the exception
051         */
052        private final Throwable rootCause;
053    
054        /**
055         * Constructs a new <code>FunctorException</code> without specified
056         * detail message.
057         */
058        public FunctorException() {
059            super();
060            this.rootCause = null;
061        }
062    
063        /**
064         * Constructs a new <code>FunctorException</code> with specified
065         * detail message.
066         *
067         * @param msg  the error message.
068         */
069        public FunctorException(String msg) {
070            super(msg);
071            this.rootCause = null;
072        }
073    
074        /**
075         * Constructs a new <code>FunctorException</code> with specified
076         * nested <code>Throwable</code> root cause.
077         *
078         * @param rootCause  the exception or error that caused this exception
079         *                   to be thrown.
080         */
081        public FunctorException(Throwable rootCause) {
082            super((rootCause == null ? null : rootCause.getMessage()));
083            this.rootCause = rootCause;
084        }
085    
086        /**
087         * Constructs a new <code>FunctorException</code> with specified
088         * detail message and nested <code>Throwable</code> root cause.
089         *
090         * @param msg        the error message.
091         * @param rootCause  the exception or error that caused this exception
092         *                   to be thrown.
093         */
094        public FunctorException(String msg, Throwable rootCause) {
095            super(msg);
096            this.rootCause = rootCause;
097        }
098    
099        /**
100         * Gets the cause of this throwable.
101         * 
102         * @return  the cause of this throwable, or <code>null</code>
103         */
104        public Throwable getCause() {
105            return rootCause;
106        }
107    
108        /**
109         * Prints the stack trace of this exception to the standard error stream.
110         */
111        public void printStackTrace() {
112            printStackTrace(System.err);
113        }
114    
115        /**
116         * Prints the stack trace of this exception to the specified stream.
117         *
118         * @param out  the <code>PrintStream</code> to use for output
119         */
120        public void printStackTrace(PrintStream out) {
121            synchronized (out) {
122                PrintWriter pw = new PrintWriter(out, false);
123                printStackTrace(pw);
124                // Flush the PrintWriter before it's GC'ed.
125                pw.flush();
126            }
127        }
128    
129        /**
130         * Prints the stack trace of this exception to the specified writer.
131         *
132         * @param out  the <code>PrintWriter</code> to use for output
133         */
134        public void printStackTrace(PrintWriter out) {
135            synchronized (out) {
136                super.printStackTrace(out);
137                if (rootCause != null && JDK_SUPPORTS_NESTED == false) {
138                    out.print("Caused by: ");
139                    rootCause.printStackTrace(out);
140                }
141            }
142        }
143    
144    }