001package org.apache.tapestry5.internal.services; 002 003import org.apache.tapestry5.services.*; 004 005import java.io.IOException; 006 007/** 008 * Filter for the {@link org.apache.tapestry5.services.RequestHandler} pipeline used to intercept and report 009 * exceptions. 010 */ 011public class RequestErrorFilter implements RequestFilter 012{ 013 private final InternalRequestGlobals internalRequestGlobals; 014 private final RequestExceptionHandler exceptionHandler; 015 016 public RequestErrorFilter(InternalRequestGlobals internalRequestGlobals, RequestExceptionHandler exceptionHandler) 017 { 018 this.internalRequestGlobals = internalRequestGlobals; 019 this.exceptionHandler = exceptionHandler; 020 } 021 022 public boolean service(Request request, Response response, RequestHandler handler) throws IOException 023 { 024 try 025 { 026 return handler.service(request, response); 027 } 028 catch (IOException ex) 029 { 030 // Pass it through. 031 throw ex; 032 } 033 catch (Throwable ex) 034 { 035 // Most of the time, we've got exception linked up the kazoo ... but when ClassLoaders 036 // get involved, things go screwy. Exceptions when transforming classes can cause 037 // a NoClassDefFoundError with no cause; here we're trying to link the cause back in. 038 // TAPESTRY-2078 039 040 Throwable exceptionToReport = attachNewCause(ex, internalRequestGlobals.getClassLoaderException()); 041 042 exceptionHandler.handleRequestException(exceptionToReport); 043 044 // We assume a reponse has been sent and there's no need to handle the request 045 // further. 046 047 return true; 048 } 049 } 050 051 private Throwable attachNewCause(Throwable exception, Throwable underlyingCause) 052 { 053 if (underlyingCause == null) return exception; 054 055 Throwable current = exception; 056 057 while (current != null) 058 { 059 060 if (current == underlyingCause) return exception; 061 062 Throwable cause = current.getCause(); 063 064 // Often, exceptions report themselves as their own cause. 065 066 if (current == cause) break; 067 068 if (cause == null) 069 { 070 071 try 072 { 073 current.initCause(underlyingCause); 074 075 return exception; 076 } 077 catch (IllegalStateException ex) 078 { 079 // TAPESTRY-2284: sometimes you just can't init the cause, and there's no way to 080 // find out without trying. 081 082 } 083 } 084 085 // Otherwise, continue working down the chain until we find a place where we can attach 086 087 current = cause; 088 } 089 090 // Found no place to report the exeption, so report the underlying cause (and lose out 091 // on all the other context). 092 093 return underlyingCause; 094 } 095}