/*
* $Id$
*
* Copyright (c) 2008 by Joel Uckelman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.tools;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Joel Uckelman
* @since 3.1.0
*/
public class ThrowableUtils {
private ThrowableUtils() {}
private static final Logger logger =
LoggerFactory.getLogger(ThrowableUtils.class);
/**
* Returns the most recent {@link Throwable} of class <code>T</code> in
* the proper causal history of the given <code>Throwable</code>, if one
* exists.
*
* @param cl the {@link Class} to search for
* @param t the <code>Throwable</code> to check
* @return the proper ancestor of class <code>T</code>, or <code>null</code>
* if none exists
*/
public static <T extends Throwable> T getAncestor(Class<T> cl, Throwable t) {
// traverse the causal history of t until a cause of type cl is found
for (Throwable c = t.getCause(); c != null; c = c.getCause()) {
if (cl.isInstance(c)) return cl.cast(c);
}
return null;
}
/**
* Returns the most recent {@link Throwable} of class <code>T</code> in
* the (not necessarily proper) causal history of the given
* <code>Throwable</code>, if one exists. If the given
* <code>Throwable</code> is of class <code>T</code>, it will be returned.
*
* @param cl the {@link Class} to search for
* @param t the <code>Throwable</code> to check
* @return the ancestor of class <code>T</code>, or <code>null</code>
* if none exists
*/
public static <T extends Throwable> T getRecent(Class<T> cl, Throwable t) {
if (cl.isInstance(t)) return cl.cast(t);
return getAncestor(cl, t);
}
/**
* Throws the most recent {@link Throwable} of class <code>T</code> in
* the proper causal history of the given <code>Throwable</code>, if one
* exists.
*
* @param cl the <code>Class</code> to search for
* @param t the <code>Throwable</code> to check
* @throws T if an ancestor of that class is found
*/
public static <T extends Throwable> void throwAncestor(
Class<T> cl, Throwable t) throws T {
final T ancestor = getAncestor(cl, t);
if (ancestor != null) throwMe(cl, t);
}
/**
* Throws the most recent {@link Throwable} of class <code>T</code> in
* the (not necessarily proper) causal history of the given
* <code>Throwable</code>, if one exists.
*
* @param cl the <code>Class</code> to search for
* @param t the <code>Throwable</code> to check
* @throws T if an ancestor of that class is found
*/
public static <T extends Throwable> void throwRecent(Class<T> cl,
Throwable t) throws T {
if (cl.isInstance(t)) throwMe(cl, t);
else throwAncestor(cl, t);
}
private static <T extends Throwable> void throwMe(Class<T> cl, Throwable t)
throws T {
T toThrow = null;
try {
toThrow = cl.cast(cl.getConstructor().newInstance().initCause(t));
}
catch (Throwable ignore) {
// If anything happens here, we're screwed anyway, as we're already
// calling this during error handling. Just log it and soldier on.
logger.warn("ignored", ignore);
}
if (toThrow != null) throw toThrow;
}
/**
* Converts a {@link Throwable}'s stack trace to a {@link String}.
*
* @param thrown the <code>Throwable</code> with the stack trace to convert
* @return the stack trace as a <code>String</code>
*/
public static String getStackTrace(Throwable thrown) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
thrown.printStackTrace(pw);
pw.flush();
return sw.toString();
}
}