View Javadoc

1   package org.apache.maven.surefire.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  /*
23   * Copyright 2002-2005 the original author or authors.
24   *
25   * Licensed under the Apache License, Version 2.0 (the "License");
26   * you may not use this file except in compliance with the License.
27   * You may obtain a copy of the License at
28   *
29   *      http://www.apache.org/licenses/LICENSE-2.0
30   *
31   * Unless required by applicable law or agreed to in writing, software
32   * distributed under the License is distributed on an "AS IS" BASIS,
33   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34   * See the License for the specific language governing permissions and
35   * limitations under the License.
36   */
37  
38  import java.io.PrintStream;
39  import java.io.PrintWriter;
40  
41  /**
42   * <p>Copied from Spring framework to keep Java 1.3 compatability.</p>
43   * <p/>
44   * <p>Handy class for wrapping runtime Exceptions with a root cause.</p>
45   * <p/>
46   * <p>This time-honoured technique is no longer necessary in Java 1.4, which
47   * finally provides built-in support for exception nesting. Thus exceptions in
48   * applications written to use Java 1.4 need not extend this class. To ease
49   * migration, this class mirrors Java 1.4's nested exceptions as closely as possible.
50   * <p/>
51   * <p>Abstract to force the programmer to extend the class. <code>getMessage</code>
52   * will include nested exception information; <code>printStackTrace</code> etc will
53   * delegate to the wrapped exception, if any.
54   * <p/>
55   * <p>The similarity between this class and the NestedCheckedException class is
56   * unavoidable, as Java forces these two classes to have different superclasses
57   * (ah, the inflexibility of concrete inheritance!).
58   * <p/>
59   * <p>As discussed in
60   * <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and
61   * Development</a>, runtime exceptions are often a better alternative to checked exceptions.
62   * However, all exceptions should preserve their stack trace, if caused by a
63   * lower-level exception.
64   *
65   * @author Rod Johnson
66   * @author Juergen Hoeller
67   * @see #getMessage
68   * @see #printStackTrace
69   * @see NestedCheckedException
70   */
71  public class NestedRuntimeException
72      extends RuntimeException
73  {
74  
75      /**
76       * Root cause of this nested exception
77       */
78      private final Throwable cause;
79  
80      /**
81       * Construct a <code>NestedRuntimeException</code> with the specified detail message
82       * and nested exception.
83       *
84       * @param msg the detail message
85       * @param ex  the nested exception
86       */
87      public NestedRuntimeException( String msg, Throwable ex )
88      {
89          super( msg );
90          this.cause = ex;
91      }
92  
93      /**
94       * Construct a <code>NestedRuntimeException</code> with the specified nested exception.
95       *
96       * @param ex the nested exception
97       */
98      public NestedRuntimeException( Throwable ex )
99      {
100         super();
101         this.cause = ex;
102     }
103 
104     /**
105      * Return the nested cause, or <code>null</code> if none.
106      * <p>Note that this will only check one level of nesting.
107      * Use <code>getRootCause()</code> to retrieve the innermost cause.
108      *
109      * @see #getRootCause()
110      */
111     public Throwable getCause()
112     {
113         // Even if you cannot set the cause of this exception other than through
114         // the constructor, we check for the cause being "this" here, as the cause
115         // could still be set to "this" via reflection: for example, by a remoting
116         // deserializer like Hessian's.
117         return ( this.cause == this ? null : this.cause );
118     }
119 
120     /**
121      * Return the detail message, including the message from the nested exception
122      * if there is one.
123      */
124     public String getMessage()
125     {
126         if ( getCause() == null )
127         {
128             return super.getMessage();
129         }
130         else
131         {
132             return super.getMessage() + "; nested exception is " + getCause().getClass().getName() + ": "
133                 + getCause().getMessage();
134         }
135     }
136 
137     /**
138      * Print the composite message and the embedded stack trace to the specified stream.
139      *
140      * @param ps the print stream
141      */
142     public void printStackTrace( PrintStream ps )
143     {
144         if ( getCause() == null )
145         {
146             super.printStackTrace( ps );
147         }
148         else
149         {
150             ps.println( this );
151             getCause().printStackTrace( ps );
152         }
153     }
154 
155     /**
156      * Print the composite message and the embedded stack trace to the specified writer.
157      *
158      * @param pw the print writer
159      */
160     public void printStackTrace( PrintWriter pw )
161     {
162         if ( getCause() == null )
163         {
164             super.printStackTrace( pw );
165         }
166         else
167         {
168             pw.println( this );
169             getCause().printStackTrace( pw );
170         }
171     }
172 
173     /**
174      * Retrieve the innermost cause of this exception, if any.
175      * <p>Currently just traverses NestedRuntimeException causes. Will use
176      * the JDK 1.4 exception cause mechanism once Spring requires JDK 1.4.
177      *
178      * @return the innermost exception, or <code>null</code> if none
179      */
180     public Throwable getRootCause()
181     {
182         Throwable cause = getCause();
183         if ( cause instanceof NestedRuntimeException )
184         {
185             return ( (NestedRuntimeException) cause ).getRootCause();
186         }
187         else
188         {
189             return cause;
190         }
191     }
192 
193     /**
194      * Check whether this exception contains an exception of the given class:
195      * either it is of the given class itself or it contains a nested cause
196      * of the given class.
197      * <p>Currently just traverses NestedRuntimeException causes. Will use
198      * the JDK 1.4 exception cause mechanism once Spring requires JDK 1.4.
199      *
200      * @param exClass the exception class to look for
201      * @return true if the class is contained
202      */
203     public boolean contains( Class exClass )
204     {
205         if ( exClass == null )
206         {
207             return false;
208         }
209         if ( exClass.isInstance( this ) )
210         {
211             return true;
212         }
213         Throwable cause = getCause();
214         if ( cause instanceof NestedRuntimeException )
215         {
216             return ( (NestedRuntimeException) cause ).contains( exClass );
217         }
218         else
219         {
220             return ( cause != null && exClass.isInstance( cause ) );
221         }
222     }
223 
224 }