0
|
1 /*--
|
|
2
|
|
3 $Id: JDOMException.java,v 1.26 2008/12/10 00:59:51 jhunter Exp $
|
|
4
|
|
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
|
|
6 All rights reserved.
|
|
7
|
|
8 Redistribution and use in source and binary forms, with or without
|
|
9 modification, are permitted provided that the following conditions
|
|
10 are met:
|
|
11
|
|
12 1. Redistributions of source code must retain the above copyright
|
|
13 notice, this list of conditions, and the following disclaimer.
|
|
14
|
|
15 2. Redistributions in binary form must reproduce the above copyright
|
|
16 notice, this list of conditions, and the disclaimer that follows
|
|
17 these conditions in the documentation and/or other materials
|
|
18 provided with the distribution.
|
|
19
|
|
20 3. The name "JDOM" must not be used to endorse or promote products
|
|
21 derived from this software without prior written permission. For
|
|
22 written permission, please contact <request_AT_jdom_DOT_org>.
|
|
23
|
|
24 4. Products derived from this software may not be called "JDOM", nor
|
|
25 may "JDOM" appear in their name, without prior written permission
|
|
26 from the JDOM Project Management <request_AT_jdom_DOT_org>.
|
|
27
|
|
28 In addition, we request (but do not require) that you include in the
|
|
29 end-user documentation provided with the redistribution and/or in the
|
|
30 software itself an acknowledgement equivalent to the following:
|
|
31 "This product includes software developed by the
|
|
32 JDOM Project (http://www.jdom.org/)."
|
|
33 Alternatively, the acknowledgment may be graphical using the logos
|
|
34 available at http://www.jdom.org/images/logos.
|
|
35
|
|
36 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
37 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
38 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
39 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
|
|
40 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
43 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
44 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
45 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
46 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
47 SUCH DAMAGE.
|
|
48
|
|
49 This software consists of voluntary contributions made by many
|
|
50 individuals on behalf of the JDOM Project and was originally
|
|
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
|
|
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
|
|
53 on the JDOM Project, please see <http://www.jdom.org/>.
|
|
54
|
|
55 */
|
|
56
|
|
57 package org.jdom;
|
|
58
|
|
59 import java.io.*;
|
|
60 import java.lang.reflect.*;
|
|
61 import java.sql.*;
|
|
62
|
|
63 import org.xml.sax.*;
|
|
64
|
|
65 /**
|
|
66 * The top level exception that JDOM classes can throw. Its subclasses add
|
|
67 * specificity to the problems that can occur using JDOM. This single exception
|
|
68 * can be caught to handle all JDOM specific problems (some methods may throw
|
|
69 * {@link java.io.IOException} and such).
|
|
70 *
|
|
71 * @version $Revision: 1.26 $, $Date: 2008/12/10 00:59:51 $
|
|
72 * @author Brett McLaughlin
|
|
73 * @author Jason Hunter
|
|
74 */
|
|
75 public class JDOMException extends Exception {
|
|
76
|
|
77 private static final String CVS_ID =
|
|
78 "@(#) $RCSfile: JDOMException.java,v $ $Revision: 1.26 $ $Date: 2008/12/10 00:59:51 $ $Name: jdom_1_1_1 $";
|
|
79
|
|
80 /** A wrapped <code>Throwable</code> */
|
|
81 private Throwable cause;
|
|
82
|
|
83 /**
|
|
84 * This will create an <code>Exception</code>.
|
|
85 */
|
|
86 public JDOMException() {
|
|
87 super("Error occurred in JDOM application.");
|
|
88 }
|
|
89
|
|
90 /**
|
|
91 * This will create an <code>Exception</code> with the given message.
|
|
92 *
|
|
93 * @param message <code>String</code> message indicating
|
|
94 * the problem that occurred.
|
|
95 */
|
|
96 public JDOMException(String message) {
|
|
97 super(message);
|
|
98 }
|
|
99
|
|
100 /**
|
|
101 * This will create an <code>Exception</code> with the given message
|
|
102 * and wrap another <code>Exception</code>. This is useful when
|
|
103 * the originating <code>Exception</code> should be held on to.
|
|
104 *
|
|
105 * @param message <code>String</code> message indicating
|
|
106 * the problem that occurred.
|
|
107 * @param cause <code>Throwable</code> that caused this
|
|
108 * to be thrown.
|
|
109 */
|
|
110 public JDOMException(String message, Throwable cause) {
|
|
111 super(message);
|
|
112 this.cause = cause;
|
|
113 }
|
|
114
|
|
115 /**
|
|
116 * Intializes the cause of this exception to be the specified value.
|
|
117 *
|
|
118 * @param cause <code>Throwable</code> that caused this
|
|
119 * to be thrown.
|
|
120 * @return a pointer to this throwable
|
|
121 */
|
|
122 // Created to match the JDK 1.4 Throwable method.
|
|
123 public Throwable initCause(Throwable cause) {
|
|
124 this.cause = cause;
|
|
125 return this;
|
|
126 }
|
|
127
|
|
128 /**
|
|
129 * This returns the message for the <code>Exception</code>. If
|
|
130 * there are one or more nested exceptions, their messages
|
|
131 * are appended.
|
|
132 *
|
|
133 * @return <code>String</code> - message for <code>Exception</code>.
|
|
134 */
|
|
135 public String getMessage() {
|
|
136 // Get this exception's message.
|
|
137 String msg = super.getMessage();
|
|
138
|
|
139 Throwable parent = this;
|
|
140 Throwable child;
|
|
141
|
|
142 // Look for nested exceptions.
|
|
143 while((child = getNestedException(parent)) != null) {
|
|
144 // Get the child's message.
|
|
145 String msg2 = child.getMessage();
|
|
146
|
|
147 // Special case: If a SAXException has no message of its own, but has a
|
|
148 // nested exception, then it returns the nested exception's message as its
|
|
149 // message. We don't want to add that message twice.
|
|
150 if (child instanceof SAXException) {
|
|
151 Throwable grandchild = ((SAXException)child).getException();
|
|
152 // If the SAXException tells us that it's message is identical to
|
|
153 // its nested exception's message, then we skip it, so we don't
|
|
154 // add it twice.
|
|
155 if (grandchild != null && msg2 != null && msg2.equals(grandchild.getMessage())) {
|
|
156 msg2 = null;
|
|
157 }
|
|
158 }
|
|
159
|
|
160 // If we found a message for the child exception, we append it.
|
|
161 if (msg2 != null) {
|
|
162 if (msg != null) {
|
|
163 msg += ": " + msg2;
|
|
164 } else {
|
|
165 msg = msg2;
|
|
166 }
|
|
167 }
|
|
168
|
|
169 // Any nested JDOMException will append its own children,
|
|
170 // so we need to break out of here.
|
|
171 if (child instanceof JDOMException) {
|
|
172 break;
|
|
173 }
|
|
174 parent = child;
|
|
175 }
|
|
176
|
|
177 // Return the completed message.
|
|
178 return msg;
|
|
179 }
|
|
180
|
|
181 /**
|
|
182 * This prints the stack trace of the <code>Exception</code>. If
|
|
183 * there is a root cause, the stack trace of the root
|
|
184 * <code>Exception</code> is printed right after.
|
|
185 */
|
|
186 public void printStackTrace() {
|
|
187 // Print the stack trace for this exception.
|
|
188 super.printStackTrace();
|
|
189
|
|
190 Throwable parent = this;
|
|
191 Throwable child;
|
|
192
|
|
193 // Print the stack trace for each nested exception.
|
|
194 while((child = getNestedException(parent)) != null) {
|
|
195 System.err.print("Caused by: ");
|
|
196 child.printStackTrace();
|
|
197 // Any nested JDOMException will print its own children,
|
|
198 // so we need to break out of here.
|
|
199 if (child instanceof JDOMException) {
|
|
200 break;
|
|
201 }
|
|
202 parent = child;
|
|
203 }
|
|
204 }
|
|
205
|
|
206 /**
|
|
207 * Prints the stack trace of the <code>Exception</code> to the given
|
|
208 * PrintStream. If there is a root cause, the stack trace of the root
|
|
209 * <code>Exception</code> is printed right after.
|
|
210 *
|
|
211 * @param s PrintStream to print to
|
|
212 */
|
|
213 public void printStackTrace(PrintStream s) {
|
|
214 // Print the stack trace for this exception.
|
|
215 super.printStackTrace(s);
|
|
216
|
|
217 Throwable parent = this;
|
|
218 Throwable child;
|
|
219
|
|
220 // Print the stack trace for each nested exception.
|
|
221 while((child = getNestedException(parent)) != null) {
|
|
222 s.print("Caused by: ");
|
|
223 child.printStackTrace(s);
|
|
224 // Any nested JDOMException will print its own children,
|
|
225 // so we need to break out of here.
|
|
226 if (child instanceof JDOMException) {
|
|
227 break;
|
|
228 }
|
|
229 parent = child;
|
|
230 }
|
|
231 }
|
|
232
|
|
233 /**
|
|
234 * Prints the stack trace of the <code>Exception</code> to the given
|
|
235 * PrintWriter. If there is a root cause, the stack trace of the root
|
|
236 * <code>Exception</code> is printed right after.
|
|
237 *
|
|
238 * @param w PrintWriter to print to
|
|
239 */
|
|
240 public void printStackTrace(PrintWriter w) {
|
|
241 // Print the stack trace for this exception.
|
|
242 super.printStackTrace(w);
|
|
243
|
|
244 Throwable parent = this;
|
|
245 Throwable child;
|
|
246
|
|
247 // Print the stack trace for each nested exception.
|
|
248 while((child = getNestedException(parent)) != null) {
|
|
249 w.print("Caused by: ");
|
|
250 child.printStackTrace(w);
|
|
251 // Any nested JDOMException will print its own children,
|
|
252 // so we need to break out of here.
|
|
253 if (child instanceof JDOMException) {
|
|
254 break;
|
|
255 }
|
|
256 parent = child;
|
|
257 }
|
|
258 }
|
|
259
|
|
260 /**
|
|
261 * This will return the root cause <code>Throwable</code>, or null
|
|
262 * if one does not exist.
|
|
263 *
|
|
264 * @return <code>Throwable</code> - the wrapped <code>Throwable</code>.
|
|
265 */
|
|
266 public Throwable getCause() {
|
|
267 return cause;
|
|
268 }
|
|
269
|
|
270 // If this Throwable has a nested (child) exception, then we return it.
|
|
271 // Otherwise we return null.
|
|
272 private static Throwable getNestedException(Throwable parent) {
|
|
273 if (parent instanceof JDOMException) {
|
|
274 return ((JDOMException)parent).getCause();
|
|
275 }
|
|
276
|
|
277 if (parent instanceof SAXException) {
|
|
278 return ((SAXException)parent).getException();
|
|
279 }
|
|
280
|
|
281 if (parent instanceof SQLException) {
|
|
282 return ((SQLException)parent).getNextException();
|
|
283 }
|
|
284
|
|
285 if (parent instanceof InvocationTargetException) {
|
|
286 return ((InvocationTargetException)parent).getTargetException();
|
|
287 }
|
|
288
|
|
289 if (parent instanceof ExceptionInInitializerError) {
|
|
290 return ((ExceptionInInitializerError)parent).getException();
|
|
291 }
|
|
292
|
|
293 // The RMI classes are not present in Android's Dalvik VM, so we use reflection to access them.
|
|
294
|
|
295 Throwable nestedException = getNestedExceptionFromField(parent, "java.rmi.RemoteException", "detail");
|
|
296 if (nestedException != null) {
|
|
297 return nestedException;
|
|
298 }
|
|
299
|
|
300 // These classes are not part of standard JDK 1.1 or 1.2, so again we use reflection to access them.
|
|
301
|
|
302 nestedException = getNestedException(parent, "javax.naming.NamingException", "getRootCause");
|
|
303 if (nestedException != null) {
|
|
304 return nestedException;
|
|
305 }
|
|
306
|
|
307 nestedException = getNestedException(parent, "javax.servlet.ServletException", "getRootCause");
|
|
308 if (nestedException != null) {
|
|
309 return nestedException;
|
|
310 }
|
|
311
|
|
312 return null;
|
|
313 }
|
|
314
|
|
315 // This method uses reflection to obtain the nest exception of a Throwable. We use reflection
|
|
316 // because the desired class may not exist in the currently-running VM.
|
|
317 private static Throwable getNestedException(
|
|
318 Throwable parent, String className, String methodName) {
|
|
319 try {
|
|
320 // See if this Throwable is of the desired type, by using isAssignableFrom().
|
|
321 Class testClass = Class.forName(className);
|
|
322 Class objectClass = parent.getClass();
|
|
323 if (testClass.isAssignableFrom(objectClass)) {
|
|
324 // Use reflection to call the specified method.
|
|
325 Class[] argClasses = new Class[0];
|
|
326 Method method = testClass.getMethod(methodName, argClasses);
|
|
327 Object[] args = new Object[0];
|
|
328 return (Throwable)method.invoke(parent, args);
|
|
329 }
|
|
330 }
|
|
331 catch(Exception ex) {
|
|
332 // Most likely, the desired class is not available in this VM. That's fine.
|
|
333 // Even if it's caused by something else, we don't want to display an error
|
|
334 // here, since we're already in the process of trying to display the original
|
|
335 // error - another error here will just confuse things.
|
|
336 }
|
|
337
|
|
338 return null;
|
|
339 }
|
|
340
|
|
341 // This method is similar to getNestedException() except it looks for a field instead
|
|
342 // of a method.
|
|
343 private static Throwable getNestedExceptionFromField(
|
|
344 Throwable parent, String className, String fieldName) {
|
|
345 try {
|
|
346 // See if this Throwable is of the desired type, by using isAssignableFrom().
|
|
347 Class testClass = Class.forName(className);
|
|
348 Class objectClass = parent.getClass();
|
|
349 if (testClass.isAssignableFrom(objectClass)) {
|
|
350 // Use reflection to call the specified method.
|
|
351 Class[] argClasses = new Class[0];
|
|
352 Field field = testClass.getField(fieldName);
|
|
353 return (Throwable)field.get(parent);
|
|
354 }
|
|
355 }
|
|
356 catch(Exception ex) {
|
|
357 // Most likely, the desired class is not available in this VM. That's fine.
|
|
358 // Could be that the named field isn't of type Throwable, but that should happen
|
|
359 // with proper call usage.
|
|
360 // Even if it's caused by something else, we don't want to display an error
|
|
361 // here, since we're already in the process of trying to display the original
|
|
362 // error - another error here will just confuse things.
|
|
363 }
|
|
364
|
|
365 return null;
|
|
366 }
|
|
367 }
|