/* * ExceptionUtils.java * */ package org.smartly.commons.util; import java.io.PrintWriter; import java.io.StringWriter; /** * @author */ public abstract class ExceptionUtils { /** * Finds the causes of an exception, ex, to see whether * any of them is the givinge type. * * @return the cause if found; null if not found */ public static Throwable findCause(Throwable ex, Class cause) { while (ex != null) { if (cause.isInstance(ex)) { return ex; } ex = getCause(ex); } return null; } /** * Returns the cause of the given throwable. It is the same as * t.getCause, but it solves the compatibility of J2EE that might not * support JDK 1.4. */ public static Throwable getCause(final Throwable ex) { if (null != ex) { final Throwable t = ex.getCause(); return t; } return null; } /** * Unveils the real cause. A throwable object is called a real cause, * if it doesn't have any cause (or called chained throwable). * * @param ex the throwable * @return the real cause; ex itself if it is already the real cause * @see #wrap */ public static Throwable getRealCause(Throwable ex) { while (true) { final Throwable cause = getCause(ex); if (cause == null) { return ex; } ex = cause; } } /** * Returns a message of the exception. */ public static String getMessage(final Throwable ex) { if (null != ex) { String s; for (Throwable t = ex; ; ) { s = t.getMessage(); if (StringUtils.hasText(s)) { break; //found } t = getCause(t); if (t == null) { break; //failed } } return s; } return null; } /** * Retrieve message of real cause. * * @param ex * @return */ public static String getRealMessage(Throwable ex) { Throwable t = getRealCause(ex); return null != t ? t.toString() : getMessage(ex); } /** * Formats the stack trace and returns the result. * Currently, it only adds the prefix to each line. * * @param prefix the prefix shown in front of each line of the stack trace; * null to denote empty */ public static String formatStackTrace(Throwable t, String prefix) { return formatStackTrace(null, t, prefix).toString(); } /** * Formats the stack trace and appends it to the specified string buffer. * * @param sb the string buffer to append the stack trace. A string buffer * will be created if null. * @param prefix the prefix shown in front of each line of the stack trace; * null to denote empty */ public static StringBuffer formatStackTrace(StringBuffer sb, Throwable t, String prefix) { return formatStackTrace(sb, t, prefix, 0); } /** * Formats the stack trace and appends it to the specified string buffer, * but only display at most maxcnt lines. * <p/> * <p>The maximal allowed number of lines is controlled by * maxcnt. Note: a stack frame is not counted, if it belongs * to java.*, javax.* or sun.*. * * @param sb the string buffer to append the stack trace. A string buffer * will be created if null. * @param prefix the prefix shown in front of each line of the stack trace; * null to denote empty * @param maxcnt the maximal allowed number of lines to dump (<=0: no limit) */ public static StringBuffer formatStackTrace(StringBuffer sb, final Throwable t, String prefix, int maxcnt) { final StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); final StringBuffer trace = sw.getBuffer(); if (prefix == null) { prefix = ""; } if (maxcnt > 0 || prefix.length() > 0) { final int len = trace.length(); if (sb == null) { sb = new StringBuffer(len + 256); } if (maxcnt <= 0) { maxcnt = Integer.MAX_VALUE; } boolean ignoreCount = false; for (int j = 0; j < len; ) { //for each line if (!ignoreCount && --maxcnt < 0) { sb.append(prefix).append("..."); break; } //StringBuffer has no indexOf(char,j), so... int k = j; while (k < len && trace.charAt(k++) != '\n') { ; //point k to the char after \n } String frame = trace.substring(j, k); sb.append(prefix).append(frame); j = k; ignoreCount = inStack(frame, "java.") || inStack(frame, "javax.") || inStack(frame, "sun."); } } else { if (sb == null) { return trace; } sb.append(trace); } return sb; } // ------------------------------------------------------------------------ // p r i v a t e // ------------------------------------------------------------------------ private static boolean inStack(String frame, String sub) { final int j = frame.indexOf(sub); if (j < 0) { return false; } if (j == 0) { return true; } final char cc = frame.charAt(j - 1); return (cc < 'a' || cc > 'z') && (cc < 'A' || cc > 'Z'); } }