001: /*--
002:
003: $Id: JDOMException.java,v 1.1 2005/04/27 09:32:38 wittek Exp $
004:
005: Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
006: All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions
010: are met:
011:
012: 1. Redistributions of source code must retain the above copyright
013: notice, this list of conditions, and the following disclaimer.
014:
015: 2. Redistributions in binary form must reproduce the above copyright
016: notice, this list of conditions, and the disclaimer that follows
017: these conditions in the documentation and/or other materials
018: provided with the distribution.
019:
020: 3. The name "JDOM" must not be used to endorse or promote products
021: derived from this software without prior written permission. For
022: written permission, please contact <request_AT_jdom_DOT_org>.
023:
024: 4. Products derived from this software may not be called "JDOM", nor
025: may "JDOM" appear in their name, without prior written permission
026: from the JDOM Project Management <request_AT_jdom_DOT_org>.
027:
028: In addition, we request (but do not require) that you include in the
029: end-user documentation provided with the redistribution and/or in the
030: software itself an acknowledgement equivalent to the following:
031: "This product includes software developed by the
032: JDOM Project (http://www.jdom.org/)."
033: Alternatively, the acknowledgment may be graphical using the logos
034: available at http://www.jdom.org/images/logos.
035:
036: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
040: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: SUCH DAMAGE.
048:
049: This software consists of voluntary contributions made by many
050: individuals on behalf of the JDOM Project and was originally
051: created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
052: Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
053: on the JDOM Project, please see <http://www.jdom.org/>.
054:
055: */
056:
057: package org.jdom;
058:
059: import java.io.*;
060: import java.lang.reflect.*;
061: import java.rmi.*;
062: import java.sql.*;
063:
064: import org.xml.sax.*;
065:
066: /**
067: * The top level exception that JDOM classes can throw. Its subclasses add
068: * specificity to the problems that can occur using JDOM. This single exception
069: * can be caught to handle all JDOM specific problems (some methods may throw
070: * {@link java.io.IOException} and such).
071: *
072: * @version $Revision: 1.1 $, $Date: 2005/04/27 09:32:38 $
073: * @author Brett McLaughlin
074: * @author Jason Hunter
075: */
076: public class JDOMException extends Exception {
077:
078: private static final String CVS_ID = "@(#) $RCSfile: JDOMException.java,v $ $Revision: 1.1 $ $Date: 2005/04/27 09:32:38 $ $Name: $";
079:
080: /** A wrapped <code>Throwable</code> */
081: private Throwable cause;
082:
083: /**
084: * This will create an <code>Exception</code>.
085: */
086: public JDOMException() {
087: super ("Error occurred in JDOM application.");
088: }
089:
090: /**
091: * This will create an <code>Exception</code> with the given message.
092: *
093: * @param message <code>String</code> message indicating
094: * the problem that occurred.
095: */
096: public JDOMException(String message) {
097: super (message);
098: }
099:
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)
152: .getException();
153: // If the SAXException tells us that it's message is identical to
154: // its nested exception's message, then we skip it, so we don't
155: // add it twice.
156: if (grandchild != null && msg2 != null
157: && msg2.equals(grandchild.getMessage())) {
158: msg2 = null;
159: }
160: }
161:
162: // If we found a message for the child exception, we append it.
163: if (msg2 != null) {
164: if (msg != null) {
165: msg += ": " + msg2;
166: } else {
167: msg = msg2;
168: }
169: }
170:
171: // Any nested JDOMException will append its own children,
172: // so we need to break out of here.
173: if (child instanceof JDOMException) {
174: break;
175: }
176: parent = child;
177: }
178:
179: // Return the completed message.
180: return msg;
181: }
182:
183: /**
184: * This prints the stack trace of the <code>Exception</code>. If
185: * there is a root cause, the stack trace of the root
186: * <code>Exception</code> is printed right after.
187: */
188: public void printStackTrace() {
189: // Print the stack trace for this exception.
190: super .printStackTrace();
191:
192: Throwable parent = this ;
193: Throwable child;
194:
195: // Print the stack trace for each nested exception.
196: while ((child = getNestedException(parent)) != null) {
197: System.err.print("Caused by: ");
198: child.printStackTrace();
199: // Any nested JDOMException will print its own children,
200: // so we need to break out of here.
201: if (child instanceof JDOMException) {
202: break;
203: }
204: parent = child;
205: }
206: }
207:
208: /**
209: * Prints the stack trace of the <code>Exception</code> to the given
210: * PrintStream. If there is a root cause, the stack trace of the root
211: * <code>Exception</code> is printed right after.
212: *
213: * @param s PrintStream to print to
214: */
215: public void printStackTrace(PrintStream s) {
216: // Print the stack trace for this exception.
217: super .printStackTrace(s);
218:
219: Throwable parent = this ;
220: Throwable child;
221:
222: // Print the stack trace for each nested exception.
223: while ((child = getNestedException(parent)) != null) {
224: s.print("Caused by: ");
225: child.printStackTrace(s);
226: // Any nested JDOMException will print its own children,
227: // so we need to break out of here.
228: if (child instanceof JDOMException) {
229: break;
230: }
231: parent = child;
232: }
233: }
234:
235: /**
236: * Prints the stack trace of the <code>Exception</code> to the given
237: * PrintWriter. If there is a root cause, the stack trace of the root
238: * <code>Exception</code> is printed right after.
239: *
240: * @param w PrintWriter to print to
241: */
242: public void printStackTrace(PrintWriter w) {
243: // Print the stack trace for this exception.
244: super .printStackTrace(w);
245:
246: Throwable parent = this ;
247: Throwable child;
248:
249: // Print the stack trace for each nested exception.
250: while ((child = getNestedException(parent)) != null) {
251: w.print("Caused by: ");
252: child.printStackTrace(w);
253: // Any nested JDOMException will print its own children,
254: // so we need to break out of here.
255: if (child instanceof JDOMException) {
256: break;
257: }
258: parent = child;
259: }
260: }
261:
262: /**
263: * This will return the root cause <code>Throwable</code>, or null
264: * if one does not exist.
265: *
266: * @return <code>Throwable</code> - the wrapped <code>Throwable</code>.
267: */
268: public Throwable getCause() {
269: return cause;
270: }
271:
272: // If this Throwable has a nested (child) exception, then we return it.
273: // Otherwise we return null.
274: private static Throwable getNestedException(Throwable parent) {
275: if (parent instanceof JDOMException) {
276: return ((JDOMException) parent).getCause();
277: }
278:
279: if (parent instanceof SAXException) {
280: return ((SAXException) parent).getException();
281: }
282:
283: if (parent instanceof SQLException) {
284: return ((SQLException) parent).getNextException();
285: }
286:
287: if (parent instanceof InvocationTargetException) {
288: return ((InvocationTargetException) parent)
289: .getTargetException();
290: }
291:
292: if (parent instanceof ExceptionInInitializerError) {
293: return ((ExceptionInInitializerError) parent)
294: .getException();
295: }
296:
297: if (parent instanceof RemoteException) {
298: return ((RemoteException) parent).detail;
299: }
300:
301: // These classes are not part of standard JDK 1.1 or 1.2, so we
302: // use reflection to access them.
303:
304: Throwable nestedException = getNestedException(parent,
305: "javax.naming.NamingException", "getRootCause");
306: if (nestedException != null) {
307: return nestedException;
308: }
309:
310: nestedException = getNestedException(parent,
311: "javax.servlet.ServletException", "getRootCause");
312: if (nestedException != null) {
313: return nestedException;
314: }
315:
316: return null;
317: }
318:
319: // This method uses reflection to obtain the nest exception of a Throwable. We use reflection
320: // because the desired class may not exist in the currently-running VM.
321: private static Throwable getNestedException(Throwable parent,
322: String className, String methodName) {
323: try {
324: // See if this Throwable is of the desired type, by using isAssignableFrom().
325: Class testClass = Class.forName(className);
326: Class objectClass = parent.getClass();
327: if (testClass.isAssignableFrom(objectClass)) {
328: // Use reflection to call the specified method.
329: Class[] argClasses = new Class[0];
330: Method method = testClass.getMethod(methodName,
331: argClasses);
332: Object[] args = new Object[0];
333: return (Throwable) method.invoke(parent, args);
334: }
335: } catch (Exception ex) {
336: // Most likely, the desired class is not available in this VM. That's fine.
337: // Even if it's caused by something else, we don't want to display an error
338: // here, since we're already in the process of trying to display the original
339: // error - another error here will just confuse things.
340: }
341:
342: return null;
343: }
344: }
|