001 package org.tynamo.exceptionpage.services; 002 003 import java.io.IOException; 004 import java.io.OutputStream; 005 006 import org.apache.tapestry5.Link; 007 import org.apache.tapestry5.internal.services.LinkSource; 008 import org.apache.tapestry5.runtime.ComponentEventException; 009 import org.apache.tapestry5.services.ComponentClassResolver; 010 import org.apache.tapestry5.services.Request; 011 import org.apache.tapestry5.services.RequestExceptionHandler; 012 import org.apache.tapestry5.services.Response; 013 import org.tynamo.exceptionpage.ContextAwareException; 014 015 public class ConfigurableRequestExceptionHandler implements RequestExceptionHandler { 016 private ExceptionHandler exceptionHandler; 017 private RequestExceptionHandler defaultRequestExceptionHandler; 018 private LinkSource linkSource; 019 private Response response; 020 private ComponentClassResolver componentClassResolver; 021 private Request request; 022 023 public ConfigurableRequestExceptionHandler(RequestExceptionHandler requestExceptionHandler, 024 ComponentClassResolver componentClassResolver, LinkSource linkSource, Request request, Response response, 025 ExceptionHandler exceptionHandler) { 026 defaultRequestExceptionHandler = requestExceptionHandler; 027 this.componentClassResolver = componentClassResolver; 028 this.linkSource = linkSource; 029 this.request = request; 030 this.response = response; 031 this.exceptionHandler = exceptionHandler; 032 } 033 034 protected Object[] formExceptionContext(Throwable exception) { 035 if (exception instanceof ContextAwareException) return ((ContextAwareException) exception).getContext(); 036 if (exception.getMessage() == null) return new Object[0]; 037 return new Object[] { exception.getMessage() }; 038 } 039 040 public void handleRequestException(Throwable exception) throws IOException { 041 Throwable cause = exception; 042 // Throw away the wrapped exceptions first 043 while (cause instanceof ComponentEventException) { 044 if (cause.getCause() == null) break; 045 cause = cause.getCause(); 046 } 047 if (!exceptionHandler.getConfiguration().containsKey(cause.getClass())) { 048 defaultRequestExceptionHandler.handleRequestException(exception); 049 return; 050 } 051 052 Link link = linkSource.createPageRenderLink(componentClassResolver.resolvePageClassNameToPageName(exceptionHandler.getConfiguration() 053 .get(cause.getClass()).getName()), false, formExceptionContext(cause)); 054 try { 055 if (request.isXHR()) { 056 OutputStream os = response.getOutputStream("application/json;charset=UTF-8"); 057 os.write(("{\"script\":\"window.location.replace('" + link.toAbsoluteURI() + "');\"}").getBytes()); 058 os.close(); 059 } else response.sendRedirect(link); 060 } 061 // This could throw exceptions if this is already a render request, but it's 062 // user's responsibility not to abuse the mechanism 063 catch (Exception e) { 064 // Nothing to do but delegate 065 defaultRequestExceptionHandler.handleRequestException(exception); 066 } 067 } 068 }