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
347
348
349
350 public static Throwable sanitize(Throwable t)
351 {
352 StackTraceElement[] trace = t.getStackTrace();
353 List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>();
354 for (StackTraceElement stackTraceElement : trace)
355 {
356 if (isMuleInternalClass(stackTraceElement.getClassName()))
357 {
358 newTrace.add(stackTraceElement);
359 }
360 }
361
362 StackTraceElement[] clean = new StackTraceElement[newTrace.size()];
363 newTrace.toArray(clean);
364 t.setStackTrace(clean);
365 return t;
366 }
367
368
369
370
371
372
373 public static Throwable summarise(Throwable t, int depth)
374 {
375 t = sanitize(t);
376 StackTraceElement[] trace = t.getStackTrace();
377
378 int newStackDepth = Math.min(trace.length, depth);
379 StackTraceElement[] newTrace = new StackTraceElement[newStackDepth];
380
381 System.arraycopy(trace, 0, newTrace, 0, newStackDepth);
382 t.setStackTrace(newTrace);
383
384 return t;
385 }
386
387 private static boolean isMuleInternalClass(String className)
388 {
389
390
391
392
393 for (String mulePackage : DefaultMuleConfiguration.stackTraceFilter)
394 {
395 if (className.startsWith(mulePackage))
396 {
397 return false;
398 }
399 }
400 return true;
401 }
402
403 public static Throwable getRootParentException(Throwable t)
404 {
405 Throwable cause = t;
406 Throwable parent = t;
407 while (cause != null)
408 {
409 if (cause.getCause() == null)
410 {
411 return parent;
412 }
413 parent = cause;
414 cause = getExceptionReader(cause).getCause(cause);
415
416 if (t == cause)
417 {
418 break;
419 }
420 }
421 return t;
422 }
423
424 public static MuleException getRootMuleException(Throwable t)
425 {
426 Throwable cause = t;
427 MuleException exception = null;
428 while (cause != null)
429 {
430 if (cause instanceof MuleException)
431 {
432 exception = (MuleException) cause;
433 }
434 cause = getExceptionReader(cause).getCause(cause);
435
436 if (t == cause)
437 {
438 break;
439 }
440 }
441 return exception;
442 }
443
444 public static List getExceptionsAsList(Throwable t)
445 {
446 List exceptions = new ArrayList();
447 Throwable cause = t;
448 while (cause != null)
449 {
450 exceptions.add(0, cause);
451 cause = getExceptionReader(cause).getCause(cause);
452
453 if (t == cause)
454 {
455 break;
456 }
457 }
458 return exceptions;
459 }
460
461 public static Map getExceptionInfo(Throwable t)
462 {
463 Map info = new HashMap();
464 Throwable cause = t;
465 while (cause != null)
466 {
467 info.putAll(getExceptionReader(cause).getInfo(cause));
468 cause = getExceptionReader(cause).getCause(cause);
469
470 if (t == cause)
471 {
472 break;
473 }
474 }
475 return info;
476 }
477
478 public static String getExceptionStack(Throwable t)
479 {
480 StringBuffer buf = new StringBuffer();
481
482 List exceptions = getExceptionsAsList(t);
483
484 int i = 1;
485 for (Iterator iterator = exceptions.iterator(); iterator.hasNext(); i++)
486 {
487 if (i > exceptionThreshold && exceptionThreshold > 0)
488 {
489 buf.append("(").append(exceptions.size() - i + 1).append(" more...)");
490 break;
491 }
492 Throwable throwable = (Throwable) iterator.next();
493 ExceptionReader er = getExceptionReader(throwable);
494 buf.append(i).append(". ").append(er.getMessage(throwable)).append(" (");
495 buf.append(throwable.getClass().getName()).append(")\n");
496 if (verbose && throwable.getStackTrace().length > 0)
497 {
498 StackTraceElement e = throwable.getStackTrace()[0];
499 buf.append(" ")
500 .append(e.getClassName())
501 .append(":")
502 .append(e.getLineNumber())
503 .append(" (")
504 .append(getJavaDocUrl(throwable.getClass()))
505 .append(")\n");
506 }
507 }
508 return buf.toString();
509 }
510
511
512
513
514
515
516 public static void registerExceptionReader(ExceptionReader reader)
517 {
518 exceptionReaders.add(reader);
519 }
520
521
522
523
524
525
526
527
528 public static ExceptionReader getExceptionReader(Throwable t)
529 {
530 for (ExceptionReader exceptionReader : exceptionReaders)
531 {
532 if (exceptionReader.getExceptionType().isInstance(t))
533 {
534 return exceptionReader;
535 }
536 }
537 return defaultExceptionReader;
538 }
539
540 public static String writeException(Throwable t)
541 {
542 ExceptionReader er = getExceptionReader(t);
543 StringBuffer msg = new StringBuffer();
544 msg.append(er.getMessage(t)).append(". Type: ").append(t.getClass());
545 return msg.toString();
546 }
547
548 public static <T extends Throwable>T unwrap(T t)
549 {
550 if(t instanceof InvocationTargetException)
551 {
552 return (T)((InvocationTargetException)t).getTargetException();
553 }
554 return t;
555
556 }
557 }