001: /*
002: * Copyright 2004-2006 OpenSymphony
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy
006: * of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations
014: * under the License.
015: */
016: package org.quartz.utils;
017:
018: import java.lang.reflect.Method;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: /**
024: * <p>
025: * Helper class for handling exception nesting, which is only supported in JDKs
026: * which are version 1.4 or later.
027: * </p>
028: *
029: * Sample usage:
030: * <pre>
031: * try {
032: * // Validate arguments
033: * } catch (Exception e) {
034: * Exception myException = new IllegalArgumentException("Doh!");
035: * ExceptionHelper.setCause(myException, e);
036: * throw myException;
037: * }
038: * </pre>
039: */
040: public class ExceptionHelper {
041: private static Boolean supportsNestedThrowable = null;
042:
043: private ExceptionHelper() {
044: }
045:
046: /**
047: * Set the given <code>Throwable<code>'s cause if this JDK supports
048: * the <code>Throwable#initCause(Throwable)</code> method.
049: */
050: public static Throwable setCause(Throwable exception,
051: Throwable cause) {
052: if (exception != null) {
053: if (supportsNestedThrowable()) {
054: try {
055: Method initCauseMethod = exception.getClass()
056: .getMethod("initCause",
057: new Class[] { Throwable.class });
058: initCauseMethod.invoke(exception,
059: new Object[] { cause });
060: } catch (Exception e) {
061: getLog()
062: .warn(
063: "Unable to invoke initCause() method on class: "
064: + exception.getClass()
065: .getName(), e);
066: }
067: }
068: }
069: return exception;
070: }
071:
072: /**
073: * Get the underlying cause <code>Throwable</code> of the given exception
074: * if this JDK supports the <code>Throwable#getCause()</code> method.
075: */
076: public static Throwable getCause(Throwable exception) {
077: if (supportsNestedThrowable()) {
078: try {
079: Method getCauseMethod = exception.getClass().getMethod(
080: "getCause", (Class[]) null);
081: return (Throwable) getCauseMethod.invoke(exception,
082: (Object[]) null);
083: } catch (Exception e) {
084: getLog().warn(
085: "Unable to invoke getCause() method on class: "
086: + exception.getClass().getName(), e);
087: }
088: }
089:
090: return null;
091: }
092:
093: /**
094: * Get whether the Throwable hierarchy for this JDK supports
095: * initCause()/getCause().
096: */
097: public static synchronized boolean supportsNestedThrowable() {
098: if (supportsNestedThrowable == null) {
099: try {
100: Throwable.class.getMethod("initCause",
101: new Class[] { Throwable.class });
102: Throwable.class.getMethod("getCause", (Class[]) null);
103: supportsNestedThrowable = Boolean.TRUE;
104: getLog().debug(
105: "Detected JDK support for nested exceptions.");
106: } catch (NoSuchMethodException e) {
107: supportsNestedThrowable = Boolean.FALSE;
108: getLog()
109: .debug(
110: "Nested exceptions are not supported by this JDK.");
111: }
112: }
113:
114: return supportsNestedThrowable.booleanValue();
115: }
116:
117: private static Log getLog() {
118: return LogFactory.getLog(ExceptionHelper.class);
119: }
120: }
|