KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > util > throwable > v1 > ChainableExceptionHelper


1 /*
2  * @(#)ChainableExceptionHelper.java
3  *
4  * Copyright (C) 2002-2003 Matt Albrecht
5  * groboclown@users.sourceforge.net
6  * http://groboutils.sourceforge.net
7  *
8  * Part of the GroboUtils package at:
9  * http://groboutils.sourceforge.net
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  */

29 package net.sourceforge.groboutils.util.throwable.v1;
30
31 import java.io.PrintStream JavaDoc;
32 import java.io.PrintWriter JavaDoc;
33 import java.io.Serializable JavaDoc;
34
35 /**
36  * Helper class to support easy-to-implement chainable exceptions. In
37  * most situations, it is close to impossible to create a generic chainable
38  * exception due to inheritance restrictions on the Java exception hierarchy
39  * (this shows a Java weakness - exception categories should be interfaces,
40  * not specific classes).
41  * <P>
42  * This will attempt to use the owning source's <tt>initCause()</tt> and
43  * <tt>getCause()</tt> methods, provided the owning source provides those
44  * methods. Only the superclass's implementation that provides these methods
45  * yet does not implement <tt>IChainableException</tt> will be used
46  * (to prevent a possible recursion nightmare).
47  * <P>
48  * In order to prevent endless recursion, this class will not look at the
49  * JDK 1.4 implementation of the source exception. This used to work with
50  * JDK 1.4.0, but JDK 1.4.2 seems to have broken the original implementation.
51  *
52  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
53  * @version $Date: 2003/05/06 05:35:01 $
54  * @since July 7, 2002
55  */

56 public class ChainableExceptionHelper implements Serializable JavaDoc
57 {
58     private Throwable JavaDoc source;
59     
60     /**
61      * The chained-to cause for this exception. Note that if the source cause
62      * is set and allows the cause to be set, then this cause will be null.
63      * If the source cannot store the cause, then this cause will be set to
64      * the correct cause, which may be <tt>null</tt>.
65      */

66     private Throwable JavaDoc cause;
67     
68     /**
69      * Flag to indicate if the cause was ever set. Needed, since the set cause
70      * may be <tt>null</tt>.
71      */

72     private boolean causeSet = false;
73     
74     
75     /**
76      * Sets the owning throwable. The initCause() method can still be
77      * called after this constructor is used.
78      */

79     public ChainableExceptionHelper( Throwable JavaDoc source )
80     {
81         if (source == null)
82         {
83             throw new IllegalArgumentException JavaDoc("no null arguments");
84         }
85         this.source = source;
86     }
87     
88     
89     public ChainableExceptionHelper( Throwable JavaDoc source, Throwable JavaDoc cause )
90     {
91         this( source );
92         initCause( cause );
93     }
94     
95     
96     /**
97      * JDK 1.4 compatible method.
98      * <P>
99      * <i>from the JDK 1.4 documentation:</i>
100      * <BLOCKQUOTE>
101      * Returns the cause of this throwable or <tt>null</tt> if the cause is
102      * nonexistent or unknown. (The cause is the throwable that caused this
103      * throwable to get thrown.)
104      * <P>
105      * This implementation returns the cause that was supplied via one of the
106      * constructors requiring a <tt>Throwable</tt>, or that was set after
107      * creation with the <tt>initCause( Throwable )</tt> method. While it is
108      * typically unnecessary to override this method, a subclass can override
109      * it to return a cause set by some other means. This is appropriate for a
110      * "legacy chained throwable" that predates the addition of chained
111      * exceptions to <tt>Throwable</tt>. Note that it is not necessary to
112      * override any of the <tt>PrintStackTrace</tt> methods, all of which
113      * invoke the getCause method to determine the cause of a throwable.
114      * </BLOCKQUOTE>
115      *
116      * @return the cause of this throwable or <tt>null</tt> if the cause is
117      * nonexistent or unknown.
118      */

119     public Throwable JavaDoc getCause()
120     {
121         Throwable JavaDoc t = null;
122         if (this.causeSet)
123         {
124             // may still be null
125
t = this.cause;
126         }
127         return t;
128     }
129     
130     
131     /**
132      * JDK 1.4 compatible method.
133      * <P>
134      * <i>from the JDK 1.4 documentation:</i>
135      * <BLOCKQUOTE>
136      * Initializes the cause of this throwable to the specified value.
137      * (The cause is the throwable that caused this throwable to get thrown.)
138      * <P>
139      * This method can be called at most once. It is generally called from
140      * within the constructor, or immediately after creating the throwable.
141      * If this throwable was created with Throwable(Throwable) or
142      * Throwable(String,Throwable), this method cannot be called even once.
143      * </BLOCKQUOTE>
144      *
145      * @param cause the cause (which is saved for later retrieval by the
146      * getCause() method). (A null value is permitted, and indicates
147      * that the cause is nonexistent or unknown.)
148      * @param source the exception that will be the underlying exception
149      * @return a reference to this Throwable instance.
150      * @exception IllegalArgumentException if cause is this throwable.
151      * (A throwable cannot be its own cause.)
152      * @exception IllegalStateException if this throwable was created with
153      * Throwable(Throwable) or Throwable(String,Throwable), or this
154      * method has already been called on this throwable.
155      */

156     public synchronized Throwable JavaDoc initCause( Throwable JavaDoc cause )
157     {
158         if (this.causeSet)
159         {
160             throw new IllegalStateException JavaDoc("Already set cause");
161         }
162         if (cause == this.source)
163         {
164             throw new IllegalArgumentException JavaDoc(
165                 "exception cannot cause itself." );
166         }
167         
168         this.causeSet = true;
169         this.cause = cause;
170         return this.source;
171     }
172     
173     
174     /**
175      * For non-JDK 1.4 compatible VMs, this overrides the original behavior
176      * to describe the underlying cause. Special logic is performed to ensure
177      * that no JDK 1.4 VM is being used when the inner exception is displayed
178      * (in order to prevent double printing).
179      */

180     public void printStackTrace( PrintStream JavaDoc ps )
181     {
182         this.source.printStackTrace( ps );
183         if (shouldDisplayCause())
184         {
185             ps.println( getUnderlyingExceptionSeparator() );
186             Throwable JavaDoc t = getCause();
187             if (t == null)
188             {
189                 ps.println( getUnknownExceptionString() );
190             }
191             else
192             {
193                 t.printStackTrace( ps );
194             }
195         }
196     }
197     
198     
199     
200     /**
201      * For non-JDK 1.4 compatible VMs, this overrides the original behavior
202      * to describe the underlying cause. Special logic is performed to ensure
203      * that no JDK 1.4 VM is being used when the inner exception is displayed
204      * (in order to prevent double printing).
205      */

206     public void printStackTrace( PrintWriter JavaDoc pw )
207     {
208         this.source.printStackTrace( pw );
209         if (shouldDisplayCause())
210         {
211             pw.println( getUnderlyingExceptionSeparator() );
212             Throwable JavaDoc t = getCause();
213             if (t == null)
214             {
215                 pw.println( getUnknownExceptionString() );
216             }
217             else
218             {
219                 t.printStackTrace( pw );
220             }
221         }
222     }
223     
224     
225     
226     protected String JavaDoc getUnderlyingExceptionSeparator()
227     {
228         return "-------- Underlying exception --------";
229     }
230     
231     
232     protected String JavaDoc getUnknownExceptionString()
233     {
234         return "Unknown or non-existent exception";
235     }
236     
237     
238     protected boolean shouldDisplayCause()
239     {
240         // if the cause was never set, then don't display the cause.
241
// if it was set (even if null), then we should display it.
242
if (!this.causeSet)
243         {
244             return false;
245         }
246         
247         // we need to do it.
248
return true;
249     }
250 }
251
252
Popular Tags