1 package org.apache.tapestry5.internal.services;
2
3 import org.apache.tapestry5.services;
4
5 import java.io.IOException;
6
7 /**
8 * Filter for the {@link org.apache.tapestry5.services.RequestHandler} pipeline used to intercept and report
9 * exceptions.
10 */
11 public class RequestErrorFilter implements RequestFilter
12 {
13 private final InternalRequestGlobals internalRequestGlobals;
14 private final RequestExceptionHandler exceptionHandler;
15
16 public RequestErrorFilter(InternalRequestGlobals internalRequestGlobals, RequestExceptionHandler exceptionHandler)
17 {
18 this.internalRequestGlobals = internalRequestGlobals;
19 this.exceptionHandler = exceptionHandler;
20 }
21
22 public boolean service(Request request, Response response, RequestHandler handler) throws IOException
23 {
24 try
25 {
26 return handler.service(request, response);
27 }
28 catch (IOException ex)
29 {
30 // Pass it through.
31 throw ex;
32 }
33 catch (Throwable ex)
34 {
35 // Most of the time, we've got exception linked up the kazoo ... but when ClassLoaders
36 // get involved, things go screwy. Exceptions when transforming classes can cause
37 // a NoClassDefFoundError with no cause; here we're trying to link the cause back in.
38 // TAPESTRY-2078
39
40 Throwable exceptionToReport = attachNewCause(ex, internalRequestGlobals.getClassLoaderException());
41
42 exceptionHandler.handleRequestException(exceptionToReport);
43
44 // We assume a reponse has been sent and there's no need to handle the request
45 // further.
46
47 return true;
48 }
49 }
50
51 private Throwable attachNewCause(Throwable exception, Throwable underlyingCause)
52 {
53 if (underlyingCause == null) return exception;
54
55 Throwable current = exception;
56
57 while (current != null)
58 {
59
60 if (current == underlyingCause) return exception;
61
62 Throwable cause = current.getCause();
63
64 // Often, exceptions report themselves as their own cause.
65
66 if (current == cause) break;
67
68 if (cause == null)
69 {
70
71 try
72 {
73 current.initCause(underlyingCause);
74
75 return exception;
76 }
77 catch (IllegalStateException ex)
78 {
79 // TAPESTRY-2284: sometimes you just can't init the cause, and there's no way to
80 // find out without trying.
81
82 }
83 }
84
85 // Otherwise, continue working down the chain until we find a place where we can attach
86
87 current = cause;
88 }
89
90 // Found no place to report the exeption, so report the underlying cause (and lose out
91 // on all the other context).
92
93 return underlyingCause;
94 }
95 }