001: /*
002: * $Id: ExceptionUtils.java,v 1.18 2007/06/07 08:27:52 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.logdoc;
008:
009: import java.lang.reflect.InvocationTargetException;
010: import java.lang.reflect.Method;
011:
012: import java.util.WeakHashMap;
013:
014: /**
015: * Utility functions related to exceptions.
016: *
017: * @version $Revision: 1.18 $ $Date: 2007/06/07 08:27:52 $
018: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
019: *
020: * @since XINS 1.2.0
021: */
022: public final class ExceptionUtils {
023:
024: /**
025: * Reference to the <code>getCause()</code> method in class
026: * <code>Throwable</code>. This reference will be <code>null</code> on Java
027: * 1.3.
028: */
029: private static Method GET_CAUSE;
030:
031: /**
032: * Reference to the <code>initCause()</code> method in class
033: * <code>Throwable</code>. This reference will be <code>null</code> on Java
034: * 1.3.
035: */
036: private static Method SET_CAUSE;
037:
038: /**
039: * Table that maps from exception to cause. This table will only be used on
040: * Java 1.3. On Java 1.4 and up it will be <code>null</code>.
041: */
042: private static WeakHashMap CAUSE_TABLE;
043:
044: /**
045: * Placeholder for the <code>null</code> object. This object will be stored
046: * in the {@link #CAUSE_TABLE} on Java 1.3 if the cause for an exception is
047: * set to <code>null</code>.
048: */
049: private static final Object NULL = new Object();
050:
051: /**
052: * Initializes this class.
053: */
054: static {
055:
056: Class[] args = new Class[] { Throwable.class };
057:
058: try {
059: GET_CAUSE = Throwable.class.getDeclaredMethod("getCause",
060: null);
061: SET_CAUSE = Throwable.class.getDeclaredMethod("initCause",
062: args);
063: CAUSE_TABLE = null;
064:
065: // Method does not exist, this is not Java 1.4
066: } catch (NoSuchMethodException exception) {
067: GET_CAUSE = null;
068: SET_CAUSE = null;
069: CAUSE_TABLE = new WeakHashMap();
070:
071: // Access denied
072: } catch (SecurityException exception) {
073: throw new RuntimeException(
074: "Unable to get getCause() method of class Throwable: Access denied by security manager.");
075: }
076: }
077:
078: /**
079: * Constructs a new <code>ExceptionUtils</code> object.
080: */
081: private ExceptionUtils() {
082: // empty
083: }
084:
085: /**
086: * Determines the root cause for the specified exception.
087: *
088: * @param exception
089: * the exception to determine the root cause for, can be
090: * <code>null</code>.
091: *
092: * @return
093: * the root cause exception, can be <code>null</code>.
094: */
095: public static Throwable getRootCause(Throwable exception) {
096:
097: // Check preconditions
098: if (exception == null) {
099: return null;
100: }
101:
102: // Get the root cause of the exception
103: Throwable cause = getCause(exception);
104: while (cause != null) {
105: exception = cause;
106: cause = getCause(exception);
107: }
108:
109: return exception;
110: }
111:
112: /**
113: * Determines the cause for the specified exception.
114: *
115: * @param exception
116: * the exception to determine the cause for, cannot be
117: * <code>null</code>.
118: *
119: * @return
120: * the cause exception, can be <code>null</code>.
121: *
122: * @throws IllegalArgumentException
123: * if <code>exception == null</code>.
124: */
125: public static Throwable getCause(Throwable exception)
126: throws IllegalArgumentException {
127:
128: // Check preconditions
129: if (exception == null) {
130: throw new IllegalArgumentException("exception == null");
131: }
132:
133: // On Java 1.4 (and up) use the Throwable.getCause() method
134: if (GET_CAUSE != null) {
135: try {
136: return (Throwable) GET_CAUSE.invoke(exception, null);
137: } catch (IllegalAccessException e) {
138: throw new RuntimeException(
139: "Unable to invoke Throwable.getCause() method. Caught IllegalAccessException.");
140: } catch (IllegalArgumentException e) {
141: throw new RuntimeException(
142: "Unable to invoke Throwable.getCause() method. Caught IllegalArgumentException");
143: } catch (InvocationTargetException e) {
144: throw new RuntimeException(
145: "Unable to invoke Throwable.getCause() method. Caught InvocationTargetException");
146: }
147:
148: // On Java 1.3 use the static table
149: } else {
150: Object cause = CAUSE_TABLE.get(exception);
151: return (cause == NULL) ? null : (Throwable) cause;
152: }
153: }
154:
155: /**
156: * Sets the cause for the specified exception.
157: *
158: * @param exception
159: * the exception to set the cause for, cannot be <code>null</code>.
160: *
161: * @param cause
162: * the cause exception, can be <code>null</code> but cannot be the
163: * same as <code>exception</code>.
164: *
165: * @throws IllegalArgumentException
166: * if <code>exception == null || exception == cause</code>.
167: *
168: * @throws IllegalStateException
169: * if the cause exception was already set.
170: */
171: public static void setCause(Throwable exception, Throwable cause)
172: throws IllegalArgumentException, IllegalStateException {
173:
174: // Check preconditions
175: if (exception == null) {
176: throw new IllegalArgumentException("exception == null");
177: }
178: if (exception == cause) {
179: throw new IllegalArgumentException("exception == cause");
180: }
181:
182: // On Java 1.4 (and up) use the Throwable.initCause() method
183: if (SET_CAUSE != null) {
184: try {
185: Object[] args = { cause };
186: SET_CAUSE.invoke(exception, args);
187: } catch (IllegalAccessException e) {
188: throw new RuntimeException(
189: "Unable to invoke Throwable.initCause() method. Caught IllegalAccessException.");
190: } catch (IllegalArgumentException e) {
191: throw new RuntimeException(
192: "Unable to invoke Throwable.initCause() method. Caught IllegalArgumentException");
193: } catch (InvocationTargetException e) {
194: Throwable targetException = e.getTargetException();
195: if (targetException instanceof RuntimeException) {
196: throw (RuntimeException) targetException;
197: } else if (targetException instanceof Error) {
198: throw (Error) targetException;
199: } else {
200: throw new RuntimeException(
201: "Unable to invoke Throwable.initCause() method. Throwable.initCause() has thrown an unexpected exception. Exception class is "
202: + targetException.getClass()
203: .getName()
204: + ". Message is: "
205: + targetException.getMessage()
206: + '.');
207: }
208: }
209:
210: // On Java 1.3 use the static table
211: } else {
212: if (CAUSE_TABLE.get(exception) != null) {
213: throw new IllegalStateException(
214: "Cause for exception already set.");
215: }
216:
217: Object value = (cause == null) ? NULL : cause;
218: CAUSE_TABLE.put(exception, value);
219: }
220: }
221: }
|