DispatcherPortlet does not forward event exceptions to the render phase by default
Issue: SPR-9287
This commit is contained in:
parent
8bd1fd3715
commit
596571059e
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -123,7 +123,7 @@ import org.springframework.web.servlet.ViewResolver;
|
||||||
* as loaded by {@link org.springframework.web.context.ContextLoaderListener},
|
* as loaded by {@link org.springframework.web.context.ContextLoaderListener},
|
||||||
* if any, will be shared.
|
* if any, will be shared.
|
||||||
*
|
*
|
||||||
* <p>Thanks to Rainer Schmitz and Nick Lothian for their suggestions!
|
* <p>Thanks to Rainer Schmitz, Nick Lothian and Eric Dalquist for their suggestions!
|
||||||
*
|
*
|
||||||
* @author William G. Thompson, Jr.
|
* @author William G. Thompson, Jr.
|
||||||
* @author John A. Lewis
|
* @author John A. Lewis
|
||||||
|
@ -241,6 +241,12 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
|
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
|
||||||
private boolean detectAllViewResolvers = true;
|
private boolean detectAllViewResolvers = true;
|
||||||
|
|
||||||
|
/** Whether exceptions thrown during doAction should be forwarded to doRender */
|
||||||
|
private boolean forwardActionException = true;
|
||||||
|
|
||||||
|
/** Whether exceptions thrown during doEvent should be forwarded to doRender */
|
||||||
|
private boolean forwardEventException = false;
|
||||||
|
|
||||||
/** URL that points to the ViewRendererServlet */
|
/** URL that points to the ViewRendererServlet */
|
||||||
private String viewRendererUrl = DEFAULT_VIEW_RENDERER_URL;
|
private String viewRendererUrl = DEFAULT_VIEW_RENDERER_URL;
|
||||||
|
|
||||||
|
@ -305,6 +311,28 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
this.detectAllViewResolvers = detectAllViewResolvers;
|
this.detectAllViewResolvers = detectAllViewResolvers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to forward exceptions thrown during the action phase
|
||||||
|
* to the render phase via a session attribute.
|
||||||
|
* <p>Default is true. Turn this off if you want the portlet container
|
||||||
|
* to provide immediate exception handling for action requests.
|
||||||
|
* @see #exposeActionException(javax.portlet.PortletRequest, javax.portlet.StateAwareResponse, Exception)
|
||||||
|
*/
|
||||||
|
public void setForwardActionException(boolean forwardActionException) {
|
||||||
|
this.forwardActionException = forwardActionException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to forward exceptions thrown during the event phase
|
||||||
|
* to the render phase via a session attribute.
|
||||||
|
* <p>Default is false. Turn this on if you want the {@link DispatcherPortlet}
|
||||||
|
* to forward the exception to the render phase, similar to what it does
|
||||||
|
* for {@link #setForwardActionException action exceptions} by default.
|
||||||
|
*/
|
||||||
|
public void setForwardEventException(boolean forwardEventException) {
|
||||||
|
this.forwardEventException = forwardEventException;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the URL to the ViewRendererServlet. That servlet is used to
|
* Set the URL to the ViewRendererServlet. That servlet is used to
|
||||||
* ultimately render all views in the portlet application.
|
* ultimately render all views in the portlet application.
|
||||||
|
@ -648,6 +676,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
// Trigger after-completion for thrown exception.
|
// Trigger after-completion for thrown exception.
|
||||||
triggerAfterActionCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
|
triggerAfterActionCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
|
||||||
// Forward the exception to the render phase to be displayed.
|
// Forward the exception to the render phase to be displayed.
|
||||||
|
if (this.forwardActionException) {
|
||||||
try {
|
try {
|
||||||
exposeActionException(request, response, ex);
|
exposeActionException(request, response, ex);
|
||||||
logger.debug("Caught exception during action phase - forwarding to render phase", ex);
|
logger.debug("Caught exception during action phase - forwarding to render phase", ex);
|
||||||
|
@ -657,6 +686,10 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (Error err) {
|
catch (Error err) {
|
||||||
PortletException ex =
|
PortletException ex =
|
||||||
new PortletException("Error occured during request processing: " + err.getMessage(), err);
|
new PortletException("Error occured during request processing: " + err.getMessage(), err);
|
||||||
|
@ -921,6 +954,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
// Trigger after-completion for thrown exception.
|
// Trigger after-completion for thrown exception.
|
||||||
triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
|
triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
|
||||||
// Forward the exception to the render phase to be displayed.
|
// Forward the exception to the render phase to be displayed.
|
||||||
|
if (this.forwardEventException) {
|
||||||
try {
|
try {
|
||||||
exposeActionException(request, response, ex);
|
exposeActionException(request, response, ex);
|
||||||
logger.debug("Caught exception during event phase - forwarding to render phase", ex);
|
logger.debug("Caught exception during event phase - forwarding to render phase", ex);
|
||||||
|
@ -930,6 +964,10 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (Error err) {
|
catch (Error err) {
|
||||||
PortletException ex =
|
PortletException ex =
|
||||||
new PortletException("Error occured during request processing: " + err.getMessage(), err);
|
new PortletException("Error occured during request processing: " + err.getMessage(), err);
|
||||||
|
@ -963,7 +1001,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
|
||||||
* Return the HandlerExecutionChain for this request.
|
* Return the HandlerExecutionChain for this request.
|
||||||
* Try all handler mappings in order.
|
* Try all handler mappings in order.
|
||||||
* @param request current portlet request
|
* @param request current portlet request
|
||||||
* @return the HandlerExceutionChain, or null if no handler could be found
|
* @return the HandlerExecutionChain, or null if no handler could be found
|
||||||
*/
|
*/
|
||||||
protected HandlerExecutionChain getHandler(PortletRequest request) throws Exception {
|
protected HandlerExecutionChain getHandler(PortletRequest request) throws Exception {
|
||||||
for (HandlerMapping hm : this.handlerMappings) {
|
for (HandlerMapping hm : this.handlerMappings) {
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.portlet;
|
package org.springframework.web.portlet;
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import javax.portlet.PortletException;
|
||||||
import javax.portlet.PortletMode;
|
import javax.portlet.PortletMode;
|
||||||
import javax.portlet.PortletSecurityException;
|
import javax.portlet.PortletSecurityException;
|
||||||
import javax.portlet.PortletSession;
|
import javax.portlet.PortletSession;
|
||||||
import javax.portlet.UnavailableException;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
@ -35,6 +34,9 @@ import org.springframework.context.i18n.LocaleContext;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.mock.web.portlet.MockActionRequest;
|
import org.springframework.mock.web.portlet.MockActionRequest;
|
||||||
import org.springframework.mock.web.portlet.MockActionResponse;
|
import org.springframework.mock.web.portlet.MockActionResponse;
|
||||||
|
import org.springframework.mock.web.portlet.MockEvent;
|
||||||
|
import org.springframework.mock.web.portlet.MockEventRequest;
|
||||||
|
import org.springframework.mock.web.portlet.MockEventResponse;
|
||||||
import org.springframework.mock.web.portlet.MockPortletConfig;
|
import org.springframework.mock.web.portlet.MockPortletConfig;
|
||||||
import org.springframework.mock.web.portlet.MockPortletContext;
|
import org.springframework.mock.web.portlet.MockPortletContext;
|
||||||
import org.springframework.mock.web.portlet.MockPortletSession;
|
import org.springframework.mock.web.portlet.MockPortletSession;
|
||||||
|
@ -139,6 +141,56 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
assertTrue(exceptionParam.startsWith(NoHandlerFoundException.class.getName()));
|
assertTrue(exceptionParam.startsWith(NoHandlerFoundException.class.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testSimpleInvalidActionRequestWithoutHandling() throws Exception {
|
||||||
|
MockActionRequest request = new MockActionRequest();
|
||||||
|
MockActionResponse response = new MockActionResponse();
|
||||||
|
request.setParameter("action", "invalid");
|
||||||
|
simpleDispatcherPortlet.setForwardActionException(false);
|
||||||
|
try {
|
||||||
|
simpleDispatcherPortlet.processAction(request, response);
|
||||||
|
fail("Should have thrown a " + NoHandlerFoundException.class);
|
||||||
|
}
|
||||||
|
catch (NoHandlerFoundException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimpleValidEventRequest() throws Exception {
|
||||||
|
MockEvent event = new MockEvent("test-event");
|
||||||
|
MockEventRequest request = new MockEventRequest(event);
|
||||||
|
MockEventResponse response = new MockEventResponse();
|
||||||
|
request.setParameter("action", "form");
|
||||||
|
simpleDispatcherPortlet.processEvent(request, response);
|
||||||
|
assertEquals("test-event", response.getRenderParameter("event"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimpleInvalidEventRequest() throws Exception {
|
||||||
|
MockEvent event = new MockEvent("test-event");
|
||||||
|
MockEventRequest request = new MockEventRequest(event);
|
||||||
|
MockEventResponse response = new MockEventResponse();
|
||||||
|
request.setParameter("action", "invalid");
|
||||||
|
try {
|
||||||
|
simpleDispatcherPortlet.processEvent(request, response);
|
||||||
|
fail("Should have thrown a " + NoHandlerFoundException.class);
|
||||||
|
}
|
||||||
|
catch (NoHandlerFoundException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimpleInvalidEventRequestWithHandling() throws Exception {
|
||||||
|
MockEvent event = new MockEvent("event");
|
||||||
|
MockEventRequest request = new MockEventRequest(event);
|
||||||
|
MockEventResponse response = new MockEventResponse();
|
||||||
|
request.setParameter("action", "invalid");
|
||||||
|
simpleDispatcherPortlet.setForwardEventException(true);
|
||||||
|
simpleDispatcherPortlet.processEvent(request, response);
|
||||||
|
String exceptionParam = response.getRenderParameter(DispatcherPortlet.ACTION_EXCEPTION_RENDER_PARAMETER);
|
||||||
|
assertNotNull(exceptionParam);
|
||||||
|
assertTrue(exceptionParam.startsWith(NoHandlerFoundException.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
public void testSimpleFormViewNoBindOnNewForm() throws Exception {
|
public void testSimpleFormViewNoBindOnNewForm() throws Exception {
|
||||||
MockRenderRequest request = new MockRenderRequest();
|
MockRenderRequest request = new MockRenderRequest();
|
||||||
MockRenderResponse response = new MockRenderResponse();
|
MockRenderResponse response = new MockRenderResponse();
|
||||||
|
@ -202,7 +254,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
fail("Should have thrown PortletSessionRequiredException");
|
fail("Should have thrown PortletSessionRequiredException");
|
||||||
}
|
}
|
||||||
catch (PortletSessionRequiredException ex) {
|
catch (PortletSessionRequiredException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +299,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
fail("Should have thrown UnavailableException");
|
fail("Should have thrown UnavailableException");
|
||||||
}
|
}
|
||||||
catch (NoHandlerFoundException ex) {
|
catch (NoHandlerFoundException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,7 +845,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
fail("Should have thrown IllegalStateException");
|
fail("Should have thrown IllegalStateException");
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
portletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
portletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
||||||
new StaticWebApplicationContext());
|
new StaticWebApplicationContext());
|
||||||
|
@ -813,7 +865,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
request.setParameter("action", "form");
|
request.setParameter("action", "form");
|
||||||
request.setParameter("age", "29");
|
request.setParameter("age", "29");
|
||||||
|
|
||||||
// see RequestContextListener.requestInitialized()
|
// see RequestContextListener.requestInitialized()
|
||||||
try {
|
try {
|
||||||
LocaleContextHolder.setLocale(request.getLocale());
|
LocaleContextHolder.setLocale(request.getLocale());
|
||||||
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
||||||
|
@ -837,7 +889,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
MockRenderResponse response = new MockRenderResponse();
|
MockRenderResponse response = new MockRenderResponse();
|
||||||
request.addPreferredLocale(Locale.GERMAN);
|
request.addPreferredLocale(Locale.GERMAN);
|
||||||
|
|
||||||
// see RequestContextListener.requestInitialized()
|
// see RequestContextListener.requestInitialized()
|
||||||
try {
|
try {
|
||||||
LocaleContextHolder.setLocale(request.getLocale());
|
LocaleContextHolder.setLocale(request.getLocale());
|
||||||
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
||||||
|
@ -863,7 +915,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
MockActionResponse response = new MockActionResponse();
|
MockActionResponse response = new MockActionResponse();
|
||||||
request.addPreferredLocale(Locale.GERMAN);
|
request.addPreferredLocale(Locale.GERMAN);
|
||||||
|
|
||||||
// see RequestContextListener.requestInitialized()
|
// see RequestContextListener.requestInitialized()
|
||||||
try {
|
try {
|
||||||
LocaleContextHolder.setLocale(request.getLocale());
|
LocaleContextHolder.setLocale(request.getLocale());
|
||||||
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
||||||
|
@ -890,7 +942,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
MockRenderResponse response = new MockRenderResponse();
|
MockRenderResponse response = new MockRenderResponse();
|
||||||
request.addPreferredLocale(Locale.GERMAN);
|
request.addPreferredLocale(Locale.GERMAN);
|
||||||
|
|
||||||
// see RequestContextListener.requestInitialized()
|
// see RequestContextListener.requestInitialized()
|
||||||
try {
|
try {
|
||||||
LocaleContextHolder.setLocale(request.getLocale());
|
LocaleContextHolder.setLocale(request.getLocale());
|
||||||
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
RequestContextHolder.setRequestAttributes(new PortletRequestAttributes(request));
|
||||||
|
@ -903,7 +955,7 @@ public class DispatcherPortletTests extends TestCase {
|
||||||
fail("should have failed to find a handler and raised an NoHandlerFoundExceptionException");
|
fail("should have failed to find a handler and raised an NoHandlerFoundExceptionException");
|
||||||
}
|
}
|
||||||
catch (NoHandlerFoundException ex) {
|
catch (NoHandlerFoundException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext());
|
assertSame(servletLocaleContext, LocaleContextHolder.getLocaleContext());
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2007 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,6 +19,8 @@ package org.springframework.web.portlet;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.portlet.EventRequest;
|
||||||
|
import javax.portlet.EventResponse;
|
||||||
import javax.portlet.RenderRequest;
|
import javax.portlet.RenderRequest;
|
||||||
import javax.portlet.RenderResponse;
|
import javax.portlet.RenderResponse;
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ import org.springframework.beans.factory.support.ManagedMap;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.web.portlet.context.StaticPortletApplicationContext;
|
import org.springframework.web.portlet.context.StaticPortletApplicationContext;
|
||||||
import org.springframework.web.portlet.handler.ParameterHandlerMapping;
|
import org.springframework.web.portlet.handler.ParameterHandlerMapping;
|
||||||
|
import org.springframework.web.portlet.mvc.EventAwareController;
|
||||||
import org.springframework.web.portlet.mvc.SimpleFormController;
|
import org.springframework.web.portlet.mvc.SimpleFormController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +89,7 @@ public class SimplePortletApplicationContext extends StaticPortletApplicationCon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class TestFormController extends SimpleFormController {
|
public static class TestFormController extends SimpleFormController implements EventAwareController {
|
||||||
|
|
||||||
TestFormController() {
|
TestFormController() {
|
||||||
super();
|
super();
|
||||||
|
@ -124,6 +127,10 @@ public class SimplePortletApplicationContext extends StaticPortletApplicationCon
|
||||||
private void writeResponse(RenderResponse response, TestBean testBean, boolean finished) throws IOException {
|
private void writeResponse(RenderResponse response, TestBean testBean, boolean finished) throws IOException {
|
||||||
response.getWriter().write((finished ? "finished" : "") + (testBean.getAge() + 5));
|
response.getWriter().write((finished ? "finished" : "") + (testBean.getAge() + 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleEventRequest(EventRequest request, EventResponse response) throws Exception {
|
||||||
|
response.setRenderParameter("event", request.getEvent().getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue