You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by ka...@apache.org on 2012/02/06 23:45:41 UTC
svn commit: r1241234 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java
test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java
Author: kaosko
Date: Mon Feb 6 22:45:40 2012
New Revision: 1241234
URL: http://svn.apache.org/viewvc?rev=1241234&view=rev
Log:
Incomplete - issue TAP5-1833: Merge functionality of Tynamo.org's
tapestry-exceptionpage module with the built-in ExceptionHandler
- add tests for handleRequestException()
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java?rev=1241234&r1=1241233&r2=1241234&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandler.java Mon Feb 6 22:45:40 2012
@@ -18,8 +18,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -31,7 +29,6 @@ import org.apache.tapestry5.ExceptionHan
import org.apache.tapestry5.Link;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.structure.Page;
-import org.apache.tapestry5.ioc.ServiceResources;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.OperationException;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -61,8 +58,6 @@ public class DefaultRequestExceptionHand
private final Response response;
- private final ServiceResources serviceResources;
-
private final ComponentClassResolver componentClassResolver;
private final LinkSource linkSource;
@@ -70,16 +65,13 @@ public class DefaultRequestExceptionHand
// should be Class<? extends Throwable>, Object but it's not allowed to configure subtypes
private final Map<Class, Object> configuration;
- private final Map<Class<ExceptionHandlerAssistant>, ExceptionHandlerAssistant> handlerAssistants = Collections
- .synchronizedMap(new HashMap<Class<ExceptionHandlerAssistant>, ExceptionHandlerAssistant>());
-
@SuppressWarnings("rawtypes")
public DefaultRequestExceptionHandler(RequestPageCache pageCache, PageResponseRenderer renderer, Logger logger,
@Symbol(SymbolConstants.EXCEPTION_REPORT_PAGE)
String pageName,
- Request request, Response response, ServiceResources serviceResources, ComponentClassResolver componentClassResolver, LinkSource linkSource, Map<Class, Object> configuration)
+ Request request, Response response, ComponentClassResolver componentClassResolver, LinkSource linkSource, Map<Class, Object> configuration)
{
this.pageCache = pageCache;
this.renderer = renderer;
@@ -87,7 +79,6 @@ public class DefaultRequestExceptionHand
this.pageName = pageName;
this.request = request;
this.response = response;
- this.serviceResources = serviceResources;
this.componentClassResolver = componentClassResolver;
this.linkSource = linkSource;
@@ -101,6 +92,12 @@ public class DefaultRequestExceptionHand
public void handleRequestException(Throwable exception) throws IOException
{
+ // skip handling of known exceptions if there are none configured
+ if (configuration.isEmpty()) {
+ renderException(exception);
+ return;
+ }
+
Throwable cause = exception;
// Depending on where the error was thrown, there could be several levels of wrappers..
@@ -129,30 +126,19 @@ public class DefaultRequestExceptionHand
Object value = configuration.get(causeClass);
Object page = null;
ExceptionHandlerAssistant assistant = null;
- if (value instanceof ExceptionHandlerAssistant) assistant = (ExceptionHandlerAssistant) value;
- else if (!(value instanceof Class)) {
- renderException(exception);
- return;
- } else if (ExceptionHandlerAssistant.class.isAssignableFrom((Class) value)) {
- @SuppressWarnings("unchecked")
- Class<ExceptionHandlerAssistant> handlerType = (Class<ExceptionHandlerAssistant>) value;
- assistant = handlerAssistants.get(handlerType);
- if (assistant == null) {
- assistant = (ExceptionHandlerAssistant) serviceResources.autobuild(handlerType);
- handlerAssistants.put(handlerType, assistant);
- }
- }
-
- // the assistant may handle the exception directly or return a page
- if (assistant != null) {
+ if (value instanceof ExceptionHandlerAssistant) {
+ assistant = (ExceptionHandlerAssistant) value;
// in case the assistant changes the context
List context = Arrays.asList(exceptionContext);
page = assistant.handleRequestException(exception, context);
exceptionContext = context.toArray();
}
- if (page == null) return;
+ else if (!(value instanceof Class)) {
+ renderException(exception);
+ return;
+ } else page = value;
- exceptionContext = new Object[0];
+ if (page == null) return;
try {
if (page instanceof Class) page = componentClassResolver.resolvePageClassNameToPageName(((Class) page).getName());
@@ -163,7 +149,7 @@ public class DefaultRequestExceptionHand
os.close();
} else response.sendRedirect(link);
}
- // This could throw exceptions if this is already a render request, but it's
+ // The above could throw an exception if we are already on a render request, but it's
// user's responsibility not to abuse the mechanism
catch (Exception e) {
// Nothing to do but delegate
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java?rev=1241234&r1=1241233&r2=1241234&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DefaultRequestExceptionHandlerTest.java Mon Feb 6 22:45:40 2012
@@ -1,15 +1,34 @@
package org.apache.tapestry5.internal.services;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
+import java.io.IOException;
+import java.security.AccessControlException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.apache.tapestry5.ContextAwareException;
+import org.apache.tapestry5.ExceptionHandlerAssistant;
+import org.apache.tapestry5.Link;
+import org.apache.tapestry5.internal.test.InternalBaseTestCase;
+import org.apache.tapestry5.services.ComponentClassResolver;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Response;
+import org.easymock.EasyMock;
+import org.slf4j.Logger;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@SuppressWarnings("serial")
-public class DefaultRequestExceptionHandlerTest {
- private DefaultRequestExceptionHandler contextFormer = new DefaultRequestExceptionHandler(null, null, null, null, null, null,
- null, null, null, null);
+public class DefaultRequestExceptionHandlerTest extends InternalBaseTestCase {
+ private Map<Class, Object> mockConfiguration = new HashMap<Class, Object>();
+ RequestPageCache pageCache = mockRequestPageCache();
+ PageResponseRenderer renderer = mockPageResponseRenderer();
+ Logger logger = mockLogger();
+ Request request = mockRequest();
+ Response response = mockResponse();
+ ComponentClassResolver componentClassResolver = mockComponentClassResolver();
+ LinkSource linkSource = mockLinkSource();
+ private DefaultRequestExceptionHandler exceptionHandler = new DefaultRequestExceptionHandler(pageCache, renderer, logger, "exceptionpage", request, response, componentClassResolver, linkSource, mockConfiguration);
private static class MyContextAwareException extends Throwable implements ContextAwareException {
private Object[] context;
@@ -23,17 +42,28 @@ public class DefaultRequestExceptionHand
}
}
+
+ private static class MyPage {
+
+ }
+
+ @BeforeClass
+ public void setup_tests() throws Exception
+ {
+ mockConfiguration.clear();
+ }
+
@Test
public void noContextWhenExceptionDoesntContainMessage() {
- Object[] context = contextFormer.formExceptionContext(new RuntimeException() {
+ Object[] context = exceptionHandler.formExceptionContext(new RuntimeException() {
});
assertEquals(context.length, 0);
}
@Test
public void contextIsExceptionMessage() {
- Object[] context = contextFormer.formExceptionContext(new RuntimeException() {
+ Object[] context = exceptionHandler.formExceptionContext(new RuntimeException() {
public String getMessage() {
return "HelloWorld";
}
@@ -44,7 +74,7 @@ public class DefaultRequestExceptionHand
@Test
public void contextIsExceptionType() {
- Object[] context = contextFormer.formExceptionContext(new IllegalArgumentException("Value not allowed"));
+ Object[] context = exceptionHandler.formExceptionContext(new IllegalArgumentException("Value not allowed"));
assertEquals(context.length, 1);
assertTrue(context[0] instanceof String);
assertTrue("illegalargument".equals(context[0]));
@@ -54,9 +84,41 @@ public class DefaultRequestExceptionHand
public void contextIsProvidedByContextAwareException() {
Object[] sourceContext = new Object[] { new Integer(10), this };
- Object[] context = contextFormer.formExceptionContext(new MyContextAwareException(sourceContext) {
+ Object[] context = exceptionHandler.formExceptionContext(new MyContextAwareException(sourceContext) {
});
assertEquals(context, sourceContext);
}
+
+ @Test
+ public void handleRequestExceptionWithConfiguredPage() throws IOException {
+ mockConfiguration.put(AccessControlException.class, MyPage.class);
+ train_resolvePageClassNameToPageName(componentClassResolver, MyPage.class.getName(), "mypage" );
+ Link link = mockLink();
+ expect(linkSource.createPageRenderLink("mypage", false, new Object[]{"accesscontrol"})).andReturn(link);
+ expect(request.isXHR()).andReturn(false);
+ response.sendRedirect(link);
+ EasyMock.expectLastCall();
+ replay();
+
+ exceptionHandler.handleRequestException(new AccessControlException("No permission"));
+ }
+
+ @Test
+ public void handleRequestExceptionWithConfiguredAssistant() throws IOException {
+ ExceptionHandlerAssistant assistant = new ExceptionHandlerAssistant() {
+ @Override
+ public Object handleRequestException(Throwable exception, List<Object> exceptionContext)
+ throws IOException
+ {
+ return null;
+ }
+ };
+
+ mockConfiguration.put(MyContextAwareException.class, assistant);
+ replay();
+
+ exceptionHandler.handleRequestException(new MyContextAwareException(new Object[]{}));
+ }
+
}