1
2
3
4
5
6
7
8
9
10
11 package org.mule.config;
12
13 import org.mule.api.MuleException;
14 import org.mule.api.MuleRuntimeException;
15 import org.mule.api.config.ExceptionReader;
16 import org.mule.api.registry.ServiceType;
17 import org.mule.config.i18n.CoreMessages;
18 import org.mule.util.ClassUtils;
19 import org.mule.util.MapUtils;
20 import org.mule.util.SpiUtils;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35
36
37
38
39
40
41
42
43
44 public final class ExceptionHelper
45 {
46
47
48
49
50
51 public static final String ERROR_CODE_PROPERTY = "error.code.property";
52
53
54
55
56 protected static final Log logger = LogFactory.getLog(ExceptionHelper.class);
57
58 private static String J2SE_VERSION = "";
59
60
61
62
63 private static final String J2EE_VERSION = "1.3ee";
64
65 private static Properties errorDocs = new Properties();
66 private static Properties errorCodes = new Properties();
67 private static Map reverseErrorCodes = null;
68 private static Map errorMappings = new HashMap();
69
70 private static int exceptionThreshold = 0;
71 private static boolean verbose = true;
72
73 private static boolean initialised = false;
74
75
76
77
78 private static List<ExceptionReader> exceptionReaders = new ArrayList<ExceptionReader>();
79
80
81
82
83 private static ExceptionReader defaultExceptionReader = new DefaultExceptionReader();
84
85 static
86 {
87 initialise();
88 }
89
90
91
92
93 private ExceptionHelper()
94 {
95
96 }
97
98 private static void initialise()
99 {
100 try
101 {
102 if (initialised)
103 {
104 return;
105 }
106
107 registerExceptionReader(new MuleExceptionReader());
108 registerExceptionReader(new NamingExceptionReader());
109 J2SE_VERSION = System.getProperty("java.specification.version");
110
111 String name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath()
112 + "/mule-exception-codes.properties";
113 InputStream in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
114 if (in == null)
115 {
116 throw new IllegalArgumentException("Failed to load resource: " + name);
117 }
118 errorCodes.load(in);
119 in.close();
120
121 reverseErrorCodes = MapUtils.invertMap(errorCodes);
122
123 name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath()
124 + "/mule-exception-config.properties";
125 in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
126 if (in == null)
127 {
128 throw new IllegalArgumentException("Failed to load resource: " + name);
129 }
130 errorDocs.load(in);
131 in.close();
132
133 initialised = true;
134 }
135 catch (Exception e)
136 {
137 throw new MuleRuntimeException(CoreMessages.failedToLoad("Exception resources"), e);
138 }
139 }
140
141 public static int getErrorCode(Class exception)
142 {
143 String code = errorCodes.getProperty(exception.getName(), "-1");
144 return Integer.parseInt(code);
145 }
146
147 public static Class getErrorClass(int code)
148 {
149 String key = String.valueOf(code);
150 Object clazz = reverseErrorCodes.get(key);
151 if (clazz == null)
152 {
153 return null;
154 }
155 else if (clazz instanceof Class)
156 {
157 return (Class) clazz;
158 }
159 else
160 {
161 try
162 {
163 clazz = ClassUtils.loadClass(clazz.toString(), ExceptionHelper.class);
164 }
165 catch (ClassNotFoundException e)
166 {
167 logger.error(e.getMessage(), e);
168 return null;
169 }
170 reverseErrorCodes.put(key, clazz);
171 return (Class) clazz;
172 }
173 }
174
175 private static Properties getErrorMappings(String protocol)
176 {
177 Object m = errorMappings.get(protocol);
178 if (m != null)
179 {
180 if (m instanceof Properties)
181 {
182 return (Properties) m;
183 }
184 else
185 {
186 return null;
187 }
188 }
189 else
190 {
191 String name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath() + "/" + protocol + "-exception-mappings.properties";
192 InputStream in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
193 if (in == null)
194 {
195 errorMappings.put(protocol, "not found");
196 if (logger.isDebugEnabled())
197 {
198 logger.debug("Failed to load error mappings from: " + name
199 + " This may be because there are no error code mappings for protocol: "
200 + protocol);
201 }
202 return null;
203 }
204
205 Properties p = new Properties();
206 try
207 {
208 p.load(in);
209 in.close();
210 }
211 catch (IOException iox)
212 {
213 throw new IllegalArgumentException("Failed to load resource: " + name);
214 }
215
216 errorMappings.put(protocol, p);
217 return p;
218 }
219 }
220
221 public static String getErrorCodePropertyName(String protocol)
222 {
223 protocol = protocol.toLowerCase();
224 Properties mappings = getErrorMappings(protocol);
225 if (mappings == null)
226 {
227 return null;
228 }
229 return mappings.getProperty(ERROR_CODE_PROPERTY);
230 }
231
232 public static String getErrorMapping(String protocol, Class exception)
233 {
234 protocol = protocol.toLowerCase();
235 Properties mappings = getErrorMappings(protocol);
236 if (mappings == null)
237 {
238 logger.info("No mappings found for protocol: " + protocol);
239 return String.valueOf(getErrorCode(exception));
240 }
241
242 Class clazz = exception;
243 String code = null;
244 while (!clazz.equals(Object.class))
245 {
246 code = mappings.getProperty(clazz.getName());
247 if (code == null)
248 {
249 clazz = clazz.getSuperclass();
250 }
251 else
252 {
253 return code;
254 }
255 }
256 code = String.valueOf(getErrorCode(exception));
257
258
259 return mappings.getProperty(code, code);
260 }
261
262 public static String getJavaDocUrl(Class<?> exception)
263 {
264 return getDocUrl("javadoc.", exception.getName());
265 }
266
267 public static String getDocUrl(Class<?> exception)
268 {
269 return getDocUrl("doc.", exception.getName());
270 }
271
272 private static String getDocUrl(String prefix, String packageName)
273 {
274 String key = prefix;
275 if (packageName.startsWith("java.") || packageName.startsWith("javax."))
276 {
277 key += J2SE_VERSION;
278 }
279 String url = getUrl(key, packageName);
280 if (url == null && (packageName.startsWith("java.") || packageName.startsWith("javax.")))
281 {
282 key = prefix + J2EE_VERSION;
283 url = getUrl(key, packageName);
284 }
285 if (url != null)
286 {
287 if (!url.endsWith("/"))
288 {
289 url += "/";
290 }
291 String s = packageName.replaceAll("[.]", "/");
292 s += ".html";
293 url += s;
294 }
295 return url;
296 }
297
298 private static String getUrl(String key, String packageName)
299 {
300 String url = null;
301 if (!key.endsWith("."))
302 {
303 key += ".";
304 }
305 while (packageName.length() > 0)
306 {
307 url = errorDocs.getProperty(key + packageName, null);
308 if (url == null)
309 {
310 int i = packageName.lastIndexOf(".");
311 if (i == -1)
312 {
313 packageName = "";
314 }
315 else
316 {
317 packageName = packageName.substring(0, i);
318 }
319 }
320 else
321 {
322 break;
323 }
324 }
325 return url;
326 }
327
328 public static Throwable getRootException(Throwable t)
329 {
330 Throwable cause = t;
331 Throwable root = null;
332 while (cause != null)
333 {
334 root = cause;
335 cause = getExceptionReader(cause).getCause(cause);
336
337 if (t == cause)
338 {
339 break;
340 }
341 }
342
343 return DefaultMuleConfiguration.fullStackTraces ? root : sanitize(root);
344 }
345
346 public static Throwable sanitizeIfNeeded(Throwable t)
347 {
348 return DefaultMuleConfiguration.fullStackTraces ? t : sanitize(t);
349 }
350
351
352
353
354
355 public static Throwable sanitize(Throwable t)
356 {
357 if (t == null)
358 {
359 return null;
360 }
361 StackTraceElement[] trace = t.getStackTrace();
362 List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>();
363 for (StackTraceElement stackTraceElement : trace)
364 {
365 if (!isMuleInternalClass(stackTraceElement.getClassName()))
366 {
367 newTrace.add(stackTraceElement);
368 }
369 }
370
371 StackTraceElement[] clean = new StackTraceElement[newTrace.size()];
372 newTrace.toArray(clean);
373 t.setStackTrace(clean);
374
375 Throwable cause = t.getCause();
376 while (cause != null)
377 {
378 sanitize(cause);
379 cause = cause.getCause();
380 }
381
382 return t;
383 }
384
385
386
387
388
389
390 public static Throwable summarise(Throwable t, int depth)
391 {
392 t = sanitize(t);
393 StackTraceElement[] trace = t.getStackTrace();
394
395 int newStackDepth = Math.min(trace.length, depth);
396 StackTraceElement[] newTrace = new StackTraceElement[newStackDepth];
397
398 System.arraycopy(trace, 0, newTrace, 0, newStackDepth);
399 t.setStackTrace(newTrace);
400
401 return t;
402 }
403
404 private static boolean isMuleInternalClass(String className)
405 {
406
407
408
409
410 for (String mulePackage : DefaultMuleConfiguration.stackTraceFilter)
411 {
412 if (className.startsWith(mulePackage))
413 {
414 return true;
415 }
416 }
417 return false;
418 }
419
420 public static Throwable getRootParentException(Throwable t)
421 {
422 Throwable cause = t;
423 Throwable parent = t;
424 while (cause != null)
425 {
426 if (cause.getCause() == null)
427 {
428 return parent;
429 }
430 parent = cause;
431 cause = getExceptionReader(cause).getCause(cause);
432
433 if (t == cause)
434 {
435 break;
436 }
437 }
438 return t;
439 }
440
441 public static MuleException getRootMuleException(Throwable t)
442 {
443 Throwable cause = t;
444 MuleException exception = null;
445 while (cause != null)
446 {
447 if (cause instanceof MuleException)
448 {
449 exception = (MuleException) cause;
450 }
451 final Throwable tempCause = getExceptionReader(cause).getCause(cause);
452 if (DefaultMuleConfiguration.fullStackTraces)
453 {
454 cause = tempCause;
455 }
456 else
457 {
458 cause = ExceptionHelper.sanitize(tempCause);
459 }
460
461 if (t == cause)
462 {
463 break;
464 }
465 }
466 return exception;
467 }
468
469 public static List getExceptionsAsList(Throwable t)
470 {
471 List exceptions = new ArrayList();
472 Throwable cause = t;
473 while (cause != null)
474 {
475 exceptions.add(0, cause);
476 cause = getExceptionReader(cause).getCause(cause);
477
478 if (t == cause)
479 {
480 break;
481 }
482 }
483 return exceptions;
484 }
485
486 public static Map getExceptionInfo(Throwable t)
487 {
488 Map info = new HashMap();
489 Throwable cause = t;
490 while (cause != null)
491 {
492 info.putAll(getExceptionReader(cause).getInfo(cause));
493 cause = getExceptionReader(cause).getCause(cause);
494
495 if (t == cause)
496 {
497 break;
498 }
499 }
500 return info;
501 }
502
503 public static String getExceptionStack(Throwable t)
504 {
505 StringBuffer buf = new StringBuffer();
506
507 List exceptions = getExceptionsAsList(t);
508
509 int i = 1;
510 for (Iterator iterator = exceptions.iterator(); iterator.hasNext(); i++)
511 {
512 if (i > exceptionThreshold && exceptionThreshold > 0)
513 {
514 buf.append("(").append(exceptions.size() - i + 1).append(" more...)");
515 break;
516 }
517 Throwable throwable = (Throwable) iterator.next();
518 ExceptionReader er = getExceptionReader(throwable);
519 buf.append(i).append(". ").append(er.getMessage(throwable)).append(" (");
520 buf.append(throwable.getClass().getName()).append(")\n");
521 if (verbose && throwable.getStackTrace().length > 0)
522 {
523 StackTraceElement e = throwable.getStackTrace()[0];
524 buf.append(" ")
525 .append(e.getClassName())
526 .append(":")
527 .append(e.getLineNumber())
528 .append(" (")
529 .append(getJavaDocUrl(throwable.getClass()))
530 .append(")\n");
531 }
532 }
533 return buf.toString();
534 }
535
536
537
538
539
540
541 public static void registerExceptionReader(ExceptionReader reader)
542 {
543 exceptionReaders.add(reader);
544 }
545
546
547
548
549
550
551
552
553 public static ExceptionReader getExceptionReader(Throwable t)
554 {
555 for (ExceptionReader exceptionReader : exceptionReaders)
556 {
557 if (exceptionReader.getExceptionType().isInstance(t))
558 {
559 return exceptionReader;
560 }
561 }
562 return defaultExceptionReader;
563 }
564
565 public static String writeException(Throwable t)
566 {
567 ExceptionReader er = getExceptionReader(t);
568 StringBuffer msg = new StringBuffer();
569 msg.append(er.getMessage(t)).append(". Type: ").append(t.getClass());
570 return msg.toString();
571 }
572
573 public static <T extends Throwable>T unwrap(T t)
574 {
575 if(t instanceof InvocationTargetException)
576 {
577 return (T)((InvocationTargetException)t).getTargetException();
578 }
579 return t;
580
581 }
582 }