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 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 043 // Initialize the Variables 044 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 045 046 final StackTraceElement[] steArr = t.getStackTrace(); 047 final StringBuilder sb = new StringBuilder(); 048 final Throwable cause = t.getCause(); 049 050 String m = t.getMessage(); 051 String lm = t.getLocalizedMessage(); 052 053 final boolean hasMessage = (m != null) && (m.length() > 0); 054 final boolean hasLMsg = (lm != null) && (lm.length() > 0); 055 056 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 057 if (hasLMsg) lm = StrIndent.indent(lm, 1, false, true); 058 059 060 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 061 // Print the "Top Part" / "Header Part" / Error-Message to the Return-Output StringBuilder 062 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 063 064 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 065 066 if (hasMessage) 067 { 068 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 069 070 if (hasLMsg && (! m.equals(lm))) 071 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 072 } 073 074 else if (hasLMsg) 075 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 076 077 else 078 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 079 080 081 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 082 // Print the Stack-Trace 083 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 084 085 sb.append(BCYAN + "StackTrace:\n" + RESET); 086 087 int temp, maxLN = 0; 088 089 for (StackTraceElement ste : steArr) 090 if ((temp = ste.getLineNumber()) > maxLN) 091 maxLN = temp; 092 093 final int base10 = 094 2 + // 2: colon + space 095 ((int) Math.ceil(Math.log10(maxLN))); 096 097 for (int k=0; k < steArr.length; k++) sb.append( 098 '\t' + StringParse.rightSpacePad(steArr[k].getLineNumber() + ":", base10) + 099 steArr[k].getClassName() + "." + 100 steArr[k].getMethodName() + "()\n" 101 ); 102 103 104 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 105 // Build the StringBuilder & Return / Exit 106 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 107 108 return (cause == null) 109 ? sb.toString() 110 : sb.toString() + StrIndent.indentTabs(toString(cause), 1); 111 } 112 113 /** 114 * Convenience Method. 115 * <BR />Invokes: {@link #toStringMaxTraces(Throwable, int)} 116 * <BR />And-Then: {@link StrIndent#indentTabs(String, int)} 117 */ 118 public static String toStringMaxTraces(Throwable t, int maxNumInvocations, int indentation) 119 { return StrIndent.indent(toStringMaxTraces(t, maxNumInvocations), indentation); } 120 121 /** 122 * Prints the {@code Exception}-message and {@code Exception}-stack trace to an output 123 * {@code String}, and invokes, recursively, this method with any cause-{@code Throwable's} 124 * that are present in this {@code Throwable}. 125 * 126 * @param t Any Java {@code Throwable}. Java {@code Throwable's} with one or {@code 'cause'} 127 * {@code Throwable's} will utilize more fully the printing-features of this class, 128 * {@code 'EXCC'} - <I>though any {@code Throwable} will be properly printed</I>. 129 * 130 * @param maxNumInvocations Each of the {@code Throwable's} printed shall have, at most, 131 * {@code 'maxNumInvocations'} of their Stack-Traces printed into the output {@code String}. 132 * 133 * @return This method doesn't actually print anything to the screen or terminal, it just 134 * returns a {@code String} that you may print yourself - <I>or write to a 135 * {@code class StringBuilder}, or any variation of text-output you wish.</I> 136 */ 137 public static String toStringMaxTraces(Throwable t, int maxNumInvocations) 138 { 139 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 140 // Initialize the Variables 141 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 142 143 StackTraceElement[] steArr = t.getStackTrace(); 144 145 final StringBuilder sb = new StringBuilder(); 146 final Throwable cause = t.getCause(); 147 148 String m = t.getMessage(); 149 String lm = t.getLocalizedMessage(); 150 151 final boolean hasMessage = (m != null) && (m.length() > 0); 152 final boolean hasLMsg = (lm != null) && (lm.length() > 0); 153 154 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 155 if (hasLMsg) lm = StrIndent.indent(lm, 1, false, true); 156 157 158 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 159 // Print the "Top Part" / "Header Part" / Error-Message to the Return-Output StringBuilder 160 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 161 162 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 163 164 if (hasMessage) 165 { 166 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 167 168 if (hasLMsg && (! m.equals(lm))) 169 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 170 } 171 172 else if (hasLMsg) 173 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 174 175 else 176 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 177 178 179 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 180 // Print the Stack-Trace 181 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 182 183 sb.append(BCYAN + "StackTrace:\n" + RESET); 184 185 int temp, maxLN = 0, stTruncated = 0; 186 187 if (steArr.length > maxNumInvocations) 188 { 189 stTruncated = steArr.length - maxNumInvocations; 190 steArr = Arrays.copyOf(steArr, maxNumInvocations); 191 } 192 193 for (StackTraceElement ste : steArr) 194 if ((temp = ste.getLineNumber()) > maxLN) 195 maxLN = temp; 196 197 final int base10 = 198 2 + // 2: colon + space 199 ((int) Math.ceil(Math.log10(maxLN))); 200 201 202 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 203 // Build the StringBuilder & Return / Exit 204 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 205 206 for (int k=0; k < steArr.length; k++) sb.append( 207 '\t' + StringParse.rightSpacePad(steArr[k].getLineNumber() + ":", base10) + 208 steArr[k].getClassName() + "." + 209 steArr[k].getMethodName() + "()\n" 210 ); 211 212 if (stTruncated > 0) 213 sb.append("\t... and " + stTruncated + " more invocations.\n"); 214 215 216 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 217 // Build the StringBuilder & Return / Exit 218 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 219 220 return (cause == null) 221 ? sb.toString() 222 : sb.toString() + StrIndent.indentTabs(toString(cause), 1); 223 } 224 225 /** 226 * Convenience Method. 227 * <BR />Invokes: {@link #toStringNoST(Throwable)} 228 * <BR />And-Then: {@link StrIndent#indentTabs(String, int)} 229 */ 230 public static String toStringNoST(Throwable t, int indentation) 231 { return StrIndent.indentTabs(toStringNoST(t), indentation); } 232 233 /** 234 * Prints the {@code Exception}-message to an output {@code String}. Invokes, recursively, 235 * this method with any cause-{@code Throwable's} that are present in this {@code Throwable}. 236 * 237 * <BR /><BR /><DIV CLASS=JDHint> 238 * This method differs from {@link #toString(Throwable)}, in that it <B>does not print the 239 * {@code StackTrace's} to the output-return {@code String}.</B> 240 * </DIV> 241 * 242 * @param t Any Java {@code Throwable}. Java {@code Throwable's} with one or {@code 'cause'} 243 * {@code Throwable's} will utilize more fully the printing-features of this class, 244 * {@code 'EXCC'} - <I>though any {@code Throwable} will be properly printed</I>. 245 * 246 * @return This method doesn't actually print anything to the screen or terminal, it just 247 * returns a {@code String} that you may print yourself - <I>or write to a 248 * {@code class StorageBuffer,} or any variation of logging you wish.</I> 249 */ 250 public static String toStringNoST(Throwable t) 251 { 252 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 253 // Initialize the Variables 254 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 255 256 final StringBuilder sb = new StringBuilder(); 257 final Throwable cause = t.getCause(); 258 259 String m = t.getMessage(); 260 String lm = t.getLocalizedMessage(); 261 262 final boolean hasMessage = (m != null) && (m.length() > 0); 263 final boolean hasLMsg = (lm != null) && (lm.length() > 0); 264 265 if (hasMessage) m = StrIndent.indent(m, 1, false, true); 266 if (hasLMsg) lm = StrIndent.indent(lm, 1, false, true); 267 268 269 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 270 // Print the "Top Part" / "Header Part" / Error-Message to the Return-Output StringBuilder 271 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 272 273 sb.append(BRED + "THROWN: " + t.getClass().getCanonicalName() + RESET + "\n"); 274 275 if (hasMessage) 276 { 277 sb.append(BCYAN + "Throwable.getMessage():\n" + RESET + m + "\n"); 278 279 if (hasLMsg && (! m.equals(lm))) 280 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 281 } 282 283 else if (hasLMsg) 284 sb.append(BCYAN + "Throwable.getLocalizedMessage():\n" + RESET + lm + "\n"); 285 286 else 287 sb.append(BYELLOW + "No Exception Messages Provided.\n" + RESET); 288 289 290 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 291 // Build the StringBuilder & Return / Exit 292 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 293 294 return (cause == null) 295 ? sb.toString() 296 : sb.toString() + StrIndent.indentTabs(toStringNoST(cause), 1); 297 } 298 299}