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