001package Torello.Java; 002 003import static Torello.Java.C.*; 004 005import java.util.Arrays; 006 007/** 008 * <B><CODE>'Exception Cause Chain'</CODE></B> helps convert exception messages whose 009 * <CODE><B>Throwable.cause()</B></CODE> method returns a non-null <CODE>cause</CODE>, thereby 010 * unrolling <I>(and printing)</I> this chain of exceptions into a readable <CODE>String</CODE>. 011 * 012 * <EMBED CLASS=external-html DATA-FILE-ID=EXCC> 013 */ 014@Torello.JavaDoc.StaticFunctional 015public class EXCC 016{ 017 private EXCC() { } 018 019 /** 020 * Convenience Method. 021 * <BR />Invokes: {@link #toString(Throwable)} 022 * <BR />And-Then: {@link StrIndent#indentTabs(String, int)} 023 */ 024 public static String toString(Throwable t, int indentation) 025 { return StrIndent.indentTabs(toString(t), indentation); } 026 027 /** 028 * Prints the {@code Exception}-message and {@code Exception}-stack trace to an output 029 * {@code String}, and invokes, recursively, this method with any cause-{@code Throwable's} 030 * that are present in this {@code Throwable}. 031 * 032 * @param t Any Java {@code Throwable}. Java {@code Throwable's} with one or {@code 'cause'} 033 * {@code Throwable's} will utilize more fully the printing-features of this class, 034 * {@code 'EXCC'} - <I>though any {@code Throwable} will be properly printed</I>. 035 * 036 * @return This method doesn't actually print anything to the screen or terminal, it just 037 * returns a {@code String} that you may print yourself - <I>or write to a 038 * {@code class StringBuilder}, or any variation of text-output you wish.</I> 039 */ 040 public static String toString(Throwable t) 041 { 042 StackTraceElement[] steArr = t.getStackTrace(); 043 StringBuilder sb = new StringBuilder(); 044 Throwable cause = t.getCause(); 045 String m = t.getMessage(); 046 String lm = t.getLocalizedMessage(); 047 boolean hasMessage = (m != null) && (m.length() > 0); 048 boolean hasLMess = (lm != null) && (lm.length() > 0); 049 050 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 051 if (hasLMess) lm = StrIndent.indent(lm, 1, false, true); 052 053 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 054 055 if (hasMessage) 056 { 057 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 058 059 if (hasLMess && (! m.equals(lm))) 060 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 061 } 062 063 else if (hasLMess) 064 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 065 066 else 067 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 068 069 sb.append(BCYAN + "StackTrace:\n" + RESET); 070 071 int temp, maxLN = 0; 072 073 for (StackTraceElement ste : steArr) 074 075 if ((temp = ste.getLineNumber()) > maxLN) 076 maxLN = temp; 077 078 int base10 = 2 /* 2: colon + space */ + ((int) Math.ceil(Math.log10(maxLN))); 079 080 for (int k=0; k < steArr.length; k++) 081 082 sb.append( 083 '\t' + StringParse.rightSpacePad(steArr[k].getLineNumber() + ":", base10) + 084 steArr[k].getClassName() + "." + 085 steArr[k].getMethodName() + "()\n" 086 ); 087 088 return (cause == null) 089 ? sb.toString() 090 : sb.toString() + StrIndent.indentTabs(toString(cause), 1); 091 } 092 093 /** 094 * Convenience Method. 095 * <BR />Invokes: {@link #toStringMaxTraces(Throwable, int)} 096 * <BR />And-Then: {@link StrIndent#indentTabs(String, int)} 097 */ 098 public static String toStringMaxTraces(Throwable t, int maxNumInvocations, int indentation) 099 { return StrIndent.indent(toStringMaxTraces(t, maxNumInvocations), indentation); } 100 101 /** 102 * Prints the {@code Exception}-message and {@code Exception}-stack trace to an output 103 * {@code String}, and invokes, recursively, this method with any cause-{@code Throwable's} 104 * that are present in this {@code Throwable}. 105 * 106 * @param t Any Java {@code Throwable}. Java {@code Throwable's} with one or {@code 'cause'} 107 * {@code Throwable's} will utilize more fully the printing-features of this class, 108 * {@code 'EXCC'} - <I>though any {@code Throwable} will be properly printed</I>. 109 * 110 * @param maxNumInvocations Each of the {@code Throwable's} printed shall have, at most, 111 * {@code 'maxNumInvocations'} of their Stack-Traces printed into the output {@code String}. 112 * 113 * @return This method doesn't actually print anything to the screen or terminal, it just 114 * returns a {@code String} that you may print yourself - <I>or write to a 115 * {@code class StringBuilder}, or any variation of text-output you wish.</I> 116 */ 117 public static String toStringMaxTraces(Throwable t, int maxNumInvocations) 118 { 119 StackTraceElement[] steArr = t.getStackTrace(); 120 StringBuilder sb = new StringBuilder(); 121 Throwable cause = t.getCause(); 122 String m = t.getMessage(); 123 String lm = t.getLocalizedMessage(); 124 boolean hasMessage = (m != null) && (m.length() > 0); 125 boolean hasLMess = (lm != null) && (lm.length() > 0); 126 127 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 128 if (hasLMess) lm = StrIndent.indent(lm, 1, false, true); 129 130 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 131 132 if (hasMessage) 133 { 134 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 135 136 if (hasLMess && (! m.equals(lm))) 137 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 138 } 139 140 else if (hasLMess) 141 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 142 143 else 144 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 145 146 sb.append(BCYAN + "StackTrace:\n" + RESET); 147 148 int temp, maxLN = 0; 149 150 int stTruncated = 0; 151 152 if (steArr.length > maxNumInvocations) 153 { 154 stTruncated = steArr.length - maxNumInvocations; 155 steArr = Arrays.copyOf(steArr, maxNumInvocations); 156 } 157 158 for (StackTraceElement ste : steArr) 159 160 if ((temp = ste.getLineNumber()) > maxLN) 161 maxLN = temp; 162 163 int base10 = 2 /* 2: colon + space */ + ((int) Math.ceil(Math.log10(maxLN))); 164 165 for (int k=0; k < steArr.length; k++) 166 167 sb.append( 168 '\t' + StringParse.rightSpacePad(steArr[k].getLineNumber() + ":", base10) + 169 steArr[k].getClassName() + "." + 170 steArr[k].getMethodName() + "()\n" 171 ); 172 173 if (stTruncated > 0) sb.append("\t... and " + stTruncated + " more invocations.\n"); 174 175 return (cause == null) 176 ? sb.toString() 177 : sb.toString() + StrIndent.indentTabs(toString(cause), 1); 178 } 179 180 /** 181 * Convenience Method. 182 * <BR />Invokes: {@link #toStringNoST(Throwable)} 183 * <BR />And-Then: {@link StrIndent#indentTabs(String, int)} 184 */ 185 public static String toStringNoST(Throwable t, int indentation) 186 { return StrIndent.indentTabs(toStringNoST(t), indentation); } 187 188 /** 189 * Prints the {@code Exception}-message to an output {@code String}. Invokes, recursively, 190 * this method with any cause-{@code Throwable's} that are present in this {@code Throwable}. 191 * 192 * <BR /><BR />This method differs from {@link #toString(Throwable)}, in that it <I>does not 193 * print the {@code StackTrace's} to the output {@code String}.</I> 194 * 195 * @param t Any Java {@code Throwable}. Java {@code Throwable's} with one or {@code 'cause'} 196 * {@code Throwable's} will utilize more fully the printing-features of this class, 197 * {@code 'EXCC'} - <I>though any {@code Throwable} will be properly printed</I>. 198 * 199 * @return This method doesn't actually print anything to the screen or terminal, it just 200 * returns a {@code String} that you may print yourself - <I>or write to a 201 * {@code class StorageBuffer,} or any variation of logging you wish.</I> 202 */ 203 public static String toStringNoST(Throwable t) 204 { 205 StringBuilder sb = new StringBuilder(); 206 Throwable cause = t.getCause(); 207 String m = t.getMessage(); 208 String lm = t.getLocalizedMessage(); 209 boolean hasMessage = (m != null) && (m.length() > 0); 210 boolean hasLMess = (lm != null) && (lm.length() > 0); 211 212 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 213 if (hasLMess) lm = StrIndent.indent(lm, 1, false, true); 214 215 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 216 217 if (hasMessage) 218 { 219 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 220 221 if (hasLMess && (! m.equals(lm))) 222 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 223 } 224 225 else if (hasLMess) 226 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 227 228 else 229 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 230 231 return (cause == null) 232 ? sb.toString() 233 : sb.toString() + StrIndent.indentTabs(toStringNoST(cause), 1); 234 } 235 236}