/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.toolkit.util.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.sql.SQLException;
/**
* 可嵌套的异常代理, 简化可嵌套的异常的实现.
*
* @author Michael Zhou
* @version $Id: ChainedThrowableDelegate.java,v 1.1 2003/07/03 07:26:22 baobao
* Exp $
*/
public class ChainedThrowableDelegate implements ChainedThrowable {
private static final long serialVersionUID = 6847759975589708959L;
/** 表示异常不存在的常量. */
protected static final Throwable NO_CAUSE = new Throwable();
/** 常见的用来取得异常起因的方法名. */
private static final String[] CAUSE_METHOD_NAMES = { "getNested", "getNestedException", "getNextException",
"getTargetException", "getException", "getSourceException", "getCausedByException", "getRootCause",
"getCause" };
/** 常见的用来取得异常起因的字段名. */
private static final String[] CAUSE_FIELD_NAMES = { "detail" };
/** 被代理的<code>Throwable</code>对象. */
protected Throwable delegatedThrowable;
/**
* 创建一个<code>Throwable</code>代理.
*
* @param throwable 被代理的异常
*/
public ChainedThrowableDelegate(Throwable throwable) {
this.delegatedThrowable = throwable;
}
/**
* 取得被代理的异常的起因.
*
* @return 异常的起因.
*/
public Throwable getCause() {
Throwable cause = getCauseByWellKnownTypes(delegatedThrowable);
for (Class throwableClass = delegatedThrowable.getClass(); cause == null
&& Throwable.class.isAssignableFrom(throwableClass); throwableClass = throwableClass.getSuperclass()) {
// 尝试常见的方法
for (int i = 0; cause == null && i < CAUSE_METHOD_NAMES.length; i++) {
cause = getCauseByMethodName(delegatedThrowable, throwableClass, CAUSE_METHOD_NAMES[i]);
}
// 尝试常见的字段
for (int i = 0; cause == null && i < CAUSE_FIELD_NAMES.length; i++) {
cause = getCauseByFieldName(delegatedThrowable, throwableClass, CAUSE_FIELD_NAMES[i]);
}
}
if (cause == delegatedThrowable) {
cause = null;
}
if (cause == NO_CAUSE) {
return null;
}
return cause;
}
/**
* 取得常见<code>Throwable</code>类的异常起因.
*
* @param throwable 异常
* @return 异常起因
*/
protected Throwable getCauseByWellKnownTypes(Throwable throwable) {
Throwable cause = null;
boolean isWellKnownType = false;
if (throwable instanceof ChainedThrowable) {
isWellKnownType = true;
cause = ((ChainedThrowable) throwable).getCause();
} else if (throwable instanceof SQLException) {
isWellKnownType = true;
cause = ((SQLException) throwable).getNextException();
} else if (throwable instanceof InvocationTargetException) {
isWellKnownType = true;
cause = ((InvocationTargetException) throwable).getTargetException();
} else if (throwable instanceof RemoteException) {
isWellKnownType = true;
cause = ((RemoteException) throwable).detail;
}
if (isWellKnownType && cause == null) {
return NO_CAUSE;
}
return cause;
}
/**
* 通过常见的方法动态地取得异常起因.
*
* @param throwable 异常
* @param throwableClass 异常类
* @param methodName 方法名
* @return 异常起因或<code>NO_CAUSE</code>
*/
protected Throwable getCauseByMethodName(Throwable throwable, Class throwableClass, String methodName) {
Method method = null;
try {
method = throwableClass.getMethod(methodName, new Class[0]);
} catch (NoSuchMethodException ignored) {
}
if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
Throwable cause = null;
try {
cause = (Throwable) method.invoke(throwable, new Object[0]);
} catch (IllegalAccessException ignored) {
} catch (IllegalArgumentException ignored) {
} catch (InvocationTargetException ignored) {
}
if (cause == null) {
return NO_CAUSE;
}
return cause;
}
return null;
}
/**
* 通过常见的方法动态地取得异常起因.
*
* @param throwable 异常
* @param throwableClass 异常类
* @param fieldName 字段名
* @return 异常起因或<code>NO_CAUSE</code>
*/
protected Throwable getCauseByFieldName(Throwable throwable, Class throwableClass, String fieldName) {
Field field = null;
try {
field = throwableClass.getField(fieldName);
} catch (NoSuchFieldException ignored) {
}
if (field != null && Throwable.class.isAssignableFrom(field.getType())) {
Throwable cause = null;
try {
cause = (Throwable) field.get(throwable);
} catch (IllegalAccessException ignored) {
} catch (IllegalArgumentException ignored) {
}
if (cause == null) {
return NO_CAUSE;
}
return cause;
}
return null;
}
/** 打印调用栈到标准错误. */
public void printStackTrace() {
ExceptionHelper.printStackTrace(this);
}
/**
* 打印调用栈到指定输出流.
*
* @param stream 输出字节流.
*/
public void printStackTrace(PrintStream stream) {
ExceptionHelper.printStackTrace(this, stream);
}
/**
* 打印调用栈到指定输出流.
*
* @param writer 输出字符流.
*/
public void printStackTrace(PrintWriter writer) {
ExceptionHelper.printStackTrace(this, writer);
}
/**
* 打印异常的调用栈, 不包括起因异常的信息.
*
* @param writer 打印到输出流
*/
public void printCurrentStackTrace(PrintWriter writer) {
if (delegatedThrowable instanceof ChainedThrowable) {
((ChainedThrowable) delegatedThrowable).printCurrentStackTrace(writer);
} else {
delegatedThrowable.printStackTrace(writer);
}
}
}