From 492c9f2246528e8c1ef5a2ef100df24ae7ee9449 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Wed, 23 Apr 2008 16:05:32 +0000 Subject: [PATCH] elimintated controller/handler adapter duplication made spring beanish with default constructor --- .../webapp/WEB-INF/config/webmvc-config.xml | 2 +- .../webapp/WEB-INF/config/webmvc-config.xml | 2 +- .../portlet/PortletExternalContext.java | 18 +- .../servlet/ServletExternalContext.java | 17 +- .../webflow/executor/FlowExecutionResult.java | 8 +- .../mvc/portlet/FlowHandlerAdapter.java | 4 +- .../mvc/servlet/AbstractFlowHandler.java | 5 + .../webflow/mvc/servlet/FlowController.java | 305 ++++-------------- .../webflow/mvc/servlet/FlowHandler.java | 8 +- .../mvc/servlet/FlowHandlerAdapter.java | 140 ++++++-- .../webflow/test/MockExternalContext.java | 17 +- .../portlet/PortletExternalContextTests.java | 18 +- .../servlet/ServletExternalContextTests.java | 18 +- .../webflow/engine/ViewStateTests.java | 12 +- .../executor/FlowExecutorImplTests.java | 16 +- .../mvc/servlet/FlowControllerTests.java | 48 ++- .../mvc/servlet/FlowHandlerAdapterTests.java | 129 ++++---- 17 files changed, 345 insertions(+), 422 deletions(-) diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webmvc-config.xml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webmvc-config.xml index 288e9475..8773dabe 100644 --- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webmvc-config.xml +++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webmvc-config.xml @@ -21,7 +21,7 @@ - + diff --git a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/config/webmvc-config.xml b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/config/webmvc-config.xml index a8dade36..201cd72b 100644 --- a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/config/webmvc-config.xml +++ b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/config/webmvc-config.xml @@ -57,7 +57,7 @@ - + \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java index 6888d7b0..5b39575c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java @@ -48,6 +48,7 @@ import org.springframework.webflow.core.collection.SharedAttributeMap; public class PortletExternalContext implements ExternalContext { protected static final short ACTION_PHASE = 1; + protected static final short RENDER_PHASE = 2; /** @@ -216,7 +217,8 @@ public class PortletExternalContext implements ExternalContext { } public boolean isResponseCommitted() { - return flowExecutionRedirectRequested() || flowDefinitionRedirectRequested() || externalRedirectRequested(); + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); } public boolean isResponseAllowed() { @@ -245,19 +247,19 @@ public class PortletExternalContext implements ExternalContext { /** * Returns the flag indicating if a flow execution redirect response has been requested by the flow. */ - public boolean flowExecutionRedirectRequested() { + public boolean getFlowExecutionRedirectRequested() { return flowExecutionRedirectRequested; } /** * Returns the flag indicating if a flow definition redirect response has been requested by the flow. */ - public boolean flowDefinitionRedirectRequested() { + public boolean getFlowDefinitionRedirectRequested() { return flowDefinitionRedirectFlowId != null; } /** - * Returns the id of the flow definition to redirect to. Only set when {@link #flowDefinitionRedirectRequested()} + * Returns the id of the flow definition to redirect to. Only set when {@link #getFlowDefinitionRedirectRequested()} * returns true. */ public String getFlowRedirectFlowId() { @@ -266,7 +268,7 @@ public class PortletExternalContext implements ExternalContext { /** * Returns the input to pass the flow definition through the redirect. Only set when - * {@link #flowDefinitionRedirectRequested()} returns true. + * {@link #getFlowDefinitionRedirectRequested()} returns true. */ public AttributeMap getFlowRedirectFlowInput() { return flowDefinitionRedirectFlowInput; @@ -275,12 +277,12 @@ public class PortletExternalContext implements ExternalContext { /** * Returns the flag indicating if an external redirect response has been requested by the flow. */ - public boolean externalRedirectRequested() { + public boolean getExternalRedirectRequested() { return externalRedirectUrl != null; } /** - * Returns the URL to redirect to. Only set if {@link #externalRedirectRequested()} returns true. + * Returns the URL to redirect to. Only set if {@link #getExternalRedirectRequested()} returns true. */ public String getExternalRedirectUrl() { return externalRedirectUrl; @@ -289,7 +291,7 @@ public class PortletExternalContext implements ExternalContext { /** * If a redirect response has been requested, indicates if the redirect should be issued from a popup dialog. */ - public boolean redirectInPopup() { + public boolean getRedirectInPopup() { return redirectInPopup; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java index 466be5de..bdeee49d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java @@ -209,7 +209,8 @@ public class ServletExternalContext implements ExternalContext { } public boolean isResponseCommitted() { - return flowExecutionRedirectRequested() || flowDefinitionRedirectRequested() || externalRedirectRequested(); + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); } public boolean isResponseAllowed() { @@ -238,19 +239,19 @@ public class ServletExternalContext implements ExternalContext { /** * Returns the flag indicating if a flow execution redirect response has been requested by the flow. */ - public boolean flowExecutionRedirectRequested() { + public boolean getFlowExecutionRedirectRequested() { return flowExecutionRedirectRequested; } /** * Returns the flag indicating if a flow definition redirect response has been requested by the flow. */ - public boolean flowDefinitionRedirectRequested() { + public boolean getFlowDefinitionRedirectRequested() { return flowDefinitionRedirectFlowId != null; } /** - * Returns the id of the flow definition to redirect to. Only set when {@link #flowDefinitionRedirectRequested()} + * Returns the id of the flow definition to redirect to. Only set when {@link #getFlowDefinitionRedirectRequested()} * returns true. */ public String getFlowRedirectFlowId() { @@ -259,7 +260,7 @@ public class ServletExternalContext implements ExternalContext { /** * Returns the input to pass the flow definition through the redirect. Only set when - * {@link #flowDefinitionRedirectRequested()} returns true. + * {@link #getFlowDefinitionRedirectRequested()} returns true. */ public AttributeMap getFlowRedirectFlowInput() { return flowDefinitionRedirectFlowInput; @@ -268,12 +269,12 @@ public class ServletExternalContext implements ExternalContext { /** * Returns the flag indicating if an external redirect response has been requested by the flow. */ - public boolean externalRedirectRequested() { + public boolean getExternalRedirectRequested() { return externalRedirectUrl != null; } /** - * Returns the URL to redirect to. Only set if {@link #externalRedirectRequested()} returns true. + * Returns the URL to redirect to. Only set if {@link #getExternalRedirectRequested()} returns true. */ public String getExternalRedirectUrl() { return externalRedirectUrl; @@ -282,7 +283,7 @@ public class ServletExternalContext implements ExternalContext { /** * If a redirect response has been requested, indicates if the redirect should be issued from a popup dialog. */ - public boolean redirectInPopup() { + public boolean getRedirectInPopup() { return redirectInPopup; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutionResult.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutionResult.java index e91c6cf1..01dc23e4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutionResult.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutionResult.java @@ -69,13 +69,13 @@ public class FlowExecutionResult { * Returns true if the flow execution paused and is now in a wait state. * @return true if paused, false if not */ - public boolean paused() { + public boolean isPaused() { return flowExecutionKey != null; } /** * Returns the key needed to resume the flow execution when a paused result. - * @see #paused() + * @see #isPaused() * @return the key of the paused flow execution */ public String getPausedKey() { @@ -86,13 +86,13 @@ public class FlowExecutionResult { * Returns true if the flow execution ended. * @return true if ended, false if not */ - public boolean ended() { + public boolean isEnded() { return flowExecutionKey == null; } /** * Returns the flow execution outcome when an ended result. - * @see #ended() + * @see #isEnded() * @return the ended outcome, or null if this is not an ended result */ public FlowExecutionOutcome getOutcome() { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java index e6b24b33..82712bd5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java @@ -105,7 +105,7 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen PortletExternalContext context = createPortletExternalContext(request, response); try { FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context); - if (result.paused()) { + if (result.isPaused()) { urlHandler.setFlowExecutionRenderParameter(result.getPausedKey(), response); } else { request.getPortletSession().setAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE, result); @@ -183,7 +183,7 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen PortletExternalContext context = createPortletExternalContext(request, response); try { FlowExecutionResult result = flowExecutor.launchExecution(flowHandler.getFlowId(), input, context); - if (result.paused()) { + if (result.isPaused()) { urlHandler.setFlowExecutionInSession(result.getPausedKey(), request); } return null; diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/AbstractFlowHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/AbstractFlowHandler.java index 51e8f7a6..02001e4c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/AbstractFlowHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/AbstractFlowHandler.java @@ -18,6 +18,7 @@ package org.springframework.webflow.mvc.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.core.style.ToStringCreator; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.FlowExecutionOutcome; @@ -47,4 +48,8 @@ public class AbstractFlowHandler implements FlowHandler { return null; } + public String toString() { + return new ToStringCreator(this).append("flowId", getFlowId()).toString(); + } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowController.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowController.java index 4271d784..17022d06 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowController.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowController.java @@ -15,31 +15,16 @@ */ package org.springframework.webflow.mvc.servlet; -import java.io.IOException; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.js.mvc.servlet.AjaxHandler; -import org.springframework.js.mvc.servlet.SpringJavascriptAjaxHandler; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; -import org.springframework.web.servlet.view.RedirectView; -import org.springframework.webflow.context.servlet.DefaultFlowUrlHandler; import org.springframework.webflow.context.servlet.FlowUrlHandler; -import org.springframework.webflow.context.servlet.ServletExternalContext; -import org.springframework.webflow.core.FlowException; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.execution.FlowExecutionOutcome; -import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException; -import org.springframework.webflow.executor.FlowExecutionResult; import org.springframework.webflow.executor.FlowExecutor; /** @@ -52,61 +37,42 @@ import org.springframework.webflow.executor.FlowExecutor; */ public class FlowController extends AbstractController { - private static final Log logger = LogFactory.getLog(FlowController.class); + private FlowHandlerAdapter flowHandlerAdapter; - /** - * The central service for executing flows and the entry point into the Web Flow system. - */ - private FlowExecutor flowExecutor; - - /** - * A strategy for extracting flow arguments and generating flow urls. - */ - private FlowUrlHandler urlHandler; - - /** - * The representation of an Ajax client service capable of interacting with web flow. - */ - private AjaxHandler ajaxHandler; - - /** - * Specific handlers this controller should delegate to, for customizing the control logic associated with managing - * the execution of a specific flow. - */ private Map flowHandlers = new HashMap(); - public FlowController() { - initDefaults(); - } - /** * Creates a new flow controller. - * @param flowExecutor the web flow executor service + * @see #setFlowExecutor(FlowExecutor) + * @see #setFlowUrlHandler(FlowUrlHandler) + * @see #setAjaxHandler(AjaxHandler) + * @see #afterPropertiesSet() */ - public FlowController(FlowExecutor flowExecutor) { - this.flowExecutor = flowExecutor; - initDefaults(); + public FlowController() { + // turn caching off for flows by default + setCacheSeconds(0); } /** - * Returns the central service for executing flows and the entry point into the Web Flow system. + * Returns the central service for executing flows. Required. */ public FlowExecutor getFlowExecutor() { - return flowExecutor; + return flowHandlerAdapter.getFlowExecutor(); } /** - * Sets the central service for executing flows and the entry point into the Web Flow system. + * Sets the central service for executing flows. Required. + * @param flowExecutor */ public void setFlowExecutor(FlowExecutor flowExecutor) { - this.flowExecutor = flowExecutor; + flowHandlerAdapter.setFlowExecutor(flowExecutor); } /** * Returns the configured flow url handler. */ public FlowUrlHandler getFlowUrlHandler() { - return urlHandler; + return flowHandlerAdapter.getFlowUrlHandler(); } /** @@ -114,14 +80,14 @@ public class FlowController extends AbstractController { * @param urlHandler the flow url handler. */ public void setFlowUrlHandler(FlowUrlHandler urlHandler) { - this.urlHandler = urlHandler; + flowHandlerAdapter.setFlowUrlHandler(urlHandler); } /** * Returns the configured Ajax handler. */ public AjaxHandler getAjaxHandler() { - return ajaxHandler; + return flowHandlerAdapter.getAjaxHandler(); } /** @@ -129,11 +95,11 @@ public class FlowController extends AbstractController { * @param ajaxHandler the ajax handler */ public void setAjaxHandler(AjaxHandler ajaxHandler) { - this.ajaxHandler = ajaxHandler; + flowHandlerAdapter.setAjaxHandler(ajaxHandler); } /** - * Sets the custom flow handles for managing access to specific flows in a custom manner. + * Sets the custom flow handles for managing the access to flows in a custom manner. * @param flowHandlers the flow handler map */ public void setFlowHandlers(Map flowHandlers) { @@ -141,203 +107,72 @@ public class FlowController extends AbstractController { } /** - * Registers a handler for managing access to a specific flow definition. - * @param handler the flow handler + * Registers a flow handler this controller should delegate to to customize the control logic associated with + * managing the execution of a specific flow. + * @param flowHandler the handler */ - public void registerFlowHandler(FlowHandler handler) { - flowHandlers.put(handler.getFlowId(), handler); + public void registerFlowHandler(FlowHandler flowHandler) { + flowHandlers.put(flowHandler.getFlowId(), flowHandler); + } + + /** + * Returns the flow handler adapter which this Controller uses internally to carry out handler workflow. + */ + public FlowHandlerAdapter getFlowHandlerAdapter() { + return flowHandlerAdapter; + } + + /** + * Sets the flow handler adapter which this Controller uses internally to carry out handler workflow. Call this + * instead of the convenience accesors to completely customize flow controller workflow. + * @param flowHandlerAdapter the flow handler adapter + */ + public void setFlowHandlerAdapter(FlowHandlerAdapter flowHandlerAdapter) { + this.flowHandlerAdapter = flowHandlerAdapter; + } + + public void afterPropertiesSet() throws Exception { + if (flowHandlerAdapter == null) { + flowHandlerAdapter = new FlowHandlerAdapter(); + flowHandlerAdapter.setApplicationContext(getApplicationContext()); + flowHandlerAdapter.afterPropertiesSet(); + } } protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { - String flowExecutionKey = urlHandler.getFlowExecutionKey(request); - if (flowExecutionKey != null) { - try { - ServletExternalContext context = createServletExternalContext(request, response); - FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context); - return handleFlowExecutionResult(result, context, request, response); - } catch (FlowException e) { - return handleFlowException(e, request, response); - } - } else { - try { - String flowId = urlHandler.getFlowId(request); - MutableAttributeMap input = getFlowInput(flowId, request); - ServletExternalContext context = createServletExternalContext(request, response); - FlowExecutionResult result = flowExecutor.launchExecution(flowId, input, context); - return handleFlowExecutionResult(result, context, request, response); - } catch (FlowException e) { - return handleFlowException(e, request, response); - } - } + FlowHandler handler = getFlowHandler(request); + return flowHandlerAdapter.handle(request, response, handler); } // subclassing hooks - protected ServletExternalContext createServletExternalContext(HttpServletRequest request, - HttpServletResponse response) { - ServletExternalContext context = new MvcExternalContext(getServletContext(), request, response, urlHandler); - context.setAjaxRequest(ajaxHandler.isAjaxRequest(getServletContext(), request, response)); - return context; - } - - protected MutableAttributeMap defaultFlowExecutionInputMap(HttpServletRequest request) { - LocalAttributeMap inputMap = new LocalAttributeMap(); - Map parameterMap = request.getParameterMap(); - Iterator it = parameterMap.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry) it.next(); - String name = (String) entry.getKey(); - String[] values = (String[]) entry.getValue(); - if (values.length == 1) { - inputMap.put(name, values[0]); - } else { - inputMap.put(name, values); - } - } - return inputMap; - } - - protected ModelAndView defaultHandleFlowOutcome(String flowId, FlowExecutionOutcome outcome, - HttpServletRequest request, HttpServletResponse response) throws IOException { - if (!response.isCommitted()) { - // by default, just start the flow over passing the output as input - if (logger.isDebugEnabled()) { - logger.debug("Restarting a new execution of ended flow '" + flowId + "'"); - } - response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, outcome.getOutput(), request)); - } - return null; - } - - protected ModelAndView defaultHandleFlowException(String flowId, FlowException e, HttpServletRequest request, - HttpServletResponse response) throws IOException { - if (e instanceof NoSuchFlowExecutionException && flowId != null) { - if (!response.isCommitted()) { - // by default, attempt to restart the flow - if (logger.isDebugEnabled()) { - logger.debug("Restarting a new execution of previously expired/ended flow '" + flowId + "'"); - } - response.sendRedirect(urlHandler.createFlowDefinitionUrl(flowId, null, request)); - } - return null; - } else { - throw e; - } - } - // internal helpers - private void initDefaults() { - urlHandler = new DefaultFlowUrlHandler(); - ajaxHandler = new SpringJavascriptAjaxHandler(); - // set the cache seconds property to 0 so no pages are cached by default for flows - setCacheSeconds(0); - } - - private ModelAndView handleFlowExecutionResult(FlowExecutionResult result, ServletExternalContext context, - HttpServletRequest request, HttpServletResponse response) throws IOException { - if (result.paused()) { - if (context.flowExecutionRedirectRequested()) { - String url = urlHandler.createFlowExecutionUrl(result.getFlowId(), result.getPausedKey(), request); - if (logger.isDebugEnabled()) { - logger.debug("Sending flow execution redirect to " + url); - } - sendRedirect(context, request, response, url); - return null; - } else if (context.externalRedirectRequested()) { - if (logger.isDebugEnabled()) { - logger.debug("Sending external redirect to " + context.getExternalRedirectUrl()); - } - sendRedirect(context, request, response, context.getExternalRedirectUrl()); - return null; - } else { - // nothing to do: flow has handled the response - return null; - } - } else if (result.ended()) { - if (context.flowDefinitionRedirectRequested()) { - String flowId = context.getFlowRedirectFlowId(); - AttributeMap input = context.getFlowRedirectFlowInput(); - String url = urlHandler.createFlowDefinitionUrl(flowId, input, request); - if (logger.isDebugEnabled()) { - logger.debug("Sending flow definition to " + url); - } - sendRedirect(context, request, response, url); - return null; - } else if (context.externalRedirectRequested()) { - if (logger.isDebugEnabled()) { - logger.debug("Sending external redirect to " + context.getExternalRedirectUrl()); - } - sendRedirect(context, request, response, context.getExternalRedirectUrl()); - return null; - } else { - return handleFlowOutcome(result.getFlowId(), result.getOutcome(), request, response); - } - } else { - throw new IllegalStateException("Execution result should have been one of [paused] or [ended]"); - } - } - - private void sendRedirect(ServletExternalContext context, HttpServletRequest request, HttpServletResponse response, - String targetUrl) throws IOException { - if (context.isAjaxRequest()) { - ajaxHandler.sendAjaxRedirect(getServletContext(), request, response, targetUrl, context.redirectInPopup()); - } else if (!response.isCommitted()) { - response.sendRedirect(response.encodeRedirectURL(targetUrl)); - } - } - - private MutableAttributeMap getFlowInput(String flowId, HttpServletRequest request) { - FlowHandler handler = getFlowHandler(flowId); - if (handler != null) { - return handler.createExecutionInputMap(request); - } else { - return defaultFlowExecutionInputMap(request); - } - } - - private ModelAndView handleFlowOutcome(String flowId, FlowExecutionOutcome outcome, HttpServletRequest request, - HttpServletResponse response) throws IOException { - FlowHandler handler = getFlowHandler(flowId); - if (handler != null) { - String location = handler.handleExecutionOutcome(outcome, request, response); - return location != null ? createRedirectView(location, request) : defaultHandleFlowOutcome(flowId, outcome, - request, response); - } else { - return defaultHandleFlowOutcome(flowId, outcome, request, response); - } - } - - private ModelAndView createRedirectView(String location, HttpServletRequest request) { - if (location.startsWith("/")) { - return new ModelAndView(new RedirectView(location, true)); - } else { - StringBuffer url = new StringBuffer(request.getServletPath()); - url.append('/'); - url.append(location); - return new ModelAndView(new RedirectView(url.toString(), true)); - } - } - - private ModelAndView handleFlowException(FlowException e, HttpServletRequest request, HttpServletResponse response) - throws IOException { + private FlowHandler getFlowHandler(HttpServletRequest request) { + FlowUrlHandler urlHandler = flowHandlerAdapter.getFlowUrlHandler(); String flowId = urlHandler.getFlowId(request); - if (flowId != null) { - FlowHandler handler = getFlowHandler(flowId); - if (handler != null) { - String location = handler.handleException(e, request, response); - return location != null ? createRedirectView(location, request) : defaultHandleFlowException(flowId, e, - request, response); - } else { - return defaultHandleFlowException(flowId, e, request, response); - } - } else { - return defaultHandleFlowException(null, e, request, response); - } + return getFlowHandler(flowId); } private FlowHandler getFlowHandler(String flowId) { - return (FlowHandler) flowHandlers.get(flowId); + FlowHandler handler = (FlowHandler) flowHandlers.get(flowId); + if (handler == null) { + handler = new DefaultFlowHandler(flowId); + } + return handler; } + + private static class DefaultFlowHandler extends AbstractFlowHandler { + private String flowId; + + public DefaultFlowHandler(String flowId) { + this.flowId = flowId; + } + + public String getFlowId() { + return flowId; + } + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandler.java index 5182bd01..fcc020b7 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandler.java @@ -58,11 +58,13 @@ public interface FlowHandler { * * Also, if the returned location no prefix, for example "/hotels/index", the location is treated as relative to the - * current servlet by default. + * current servlet by default + *

+ * For servlet-relative and context-relative URLs, a leading slash is optional. * * @param outcome the outcome that was reached * @param request the current request diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapter.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapter.java index 0f6b3d59..ad2e8296 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapter.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapter.java @@ -24,8 +24,10 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.js.mvc.servlet.AjaxHandler; import org.springframework.js.mvc.servlet.SpringJavascriptAjaxHandler; +import org.springframework.util.Assert; import org.springframework.web.context.support.WebApplicationObjectSupport; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; @@ -48,7 +50,7 @@ import org.springframework.webflow.executor.FlowExecutor; * * @author Keith Donald */ -public class FlowHandlerAdapter extends WebApplicationObjectSupport implements HandlerAdapter { +public class FlowHandlerAdapter extends WebApplicationObjectSupport implements HandlerAdapter, InitializingBean { private static final Log logger = LogFactory.getLog(FlowHandlerAdapter.class); @@ -68,13 +70,28 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H private AjaxHandler ajaxHandler; /** - * Creates a new flow handler adapter - * @param flowExecutor the flow executor + * Creates a new flow handler adapter. + * @see #setFlowExecutor(FlowExecutor) + * @see #setFlowUrlHandler(FlowUrlHandler) + * @see #setAjaxHandler(AjaxHandler) + * @see #afterPropertiesSet() */ - public FlowHandlerAdapter(FlowExecutor flowExecutor) { + public FlowHandlerAdapter() { + } + + /** + * Returns the central service for executing flows. Required. + */ + public FlowExecutor getFlowExecutor() { + return flowExecutor; + } + + /** + * Sets the central service for executing flows. Required. + * @param flowExecutor + */ + public void setFlowExecutor(FlowExecutor flowExecutor) { this.flowExecutor = flowExecutor; - this.urlHandler = new DefaultFlowUrlHandler(); - this.ajaxHandler = new SpringJavascriptAjaxHandler(); } /** @@ -107,6 +124,16 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H this.ajaxHandler = ajaxHandler; } + public void afterPropertiesSet() throws Exception { + Assert.notNull(flowExecutor, "The FlowExecutor to execute flows is required"); + if (urlHandler == null) { + this.urlHandler = new DefaultFlowUrlHandler(); + } + if (ajaxHandler == null) { + this.ajaxHandler = new SpringJavascriptAjaxHandler(); + } + } + public boolean supports(Object handler) { return handler instanceof FlowHandler; } @@ -138,6 +165,11 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H // subclassing hooks + /** + * Creates the servlet external context for the current HTTP servlet request. + * @param request the current request + * @param response the current response + */ protected ServletExternalContext createServletExternalContext(HttpServletRequest request, HttpServletResponse response) { ServletExternalContext context = new MvcExternalContext(getServletContext(), request, response, urlHandler); @@ -145,9 +177,28 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H return context; } - protected MutableAttributeMap defaultFlowExecutionInputMap(HttpServletRequest request) { - LocalAttributeMap inputMap = new LocalAttributeMap(); + /** + * The default algorithm to determine the id of the flow to launch from the current request. Only called if + * {@link FlowHandler#getFlowId()} returns null. This implementation delegates to the configured + * {@link FlowUrlHandler#getFlowId(HttpServletRequest)}. + * @param request the current request + */ + protected String defaultGetFlowId(HttpServletRequest request) { + return urlHandler.getFlowId(request); + } + + /** + * The default algorithm to create the flow execution input map. Only called if + * {@link FlowHandler#createExecutionInputMap(HttpServletRequest)} returns null. This implementation exposes all + * current request parameters as flow execution input attributes. + * @param request the current request + */ + protected MutableAttributeMap defaultCreateFlowExecutionInputMap(HttpServletRequest request) { Map parameterMap = request.getParameterMap(); + if (parameterMap.size() == 0) { + return null; + } + LocalAttributeMap inputMap = new LocalAttributeMap(parameterMap.size(), 1); Iterator it = parameterMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); @@ -162,7 +213,17 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H return inputMap; } - protected ModelAndView defaultHandleFlowOutcome(String flowId, FlowExecutionOutcome outcome, + /** + * The default algorithm for handling a flow execution outcome. Only called if + * {@link FlowHandler#handleExecutionOutcome(FlowExecutionOutcome, HttpServletRequest, HttpServletResponse)} returns + * null. This implementation attempts to start a new execution of the ended flow. Any flow execution output is + * passed as input to the new execution. + * @param flowId the id of the ended flow + * @param outcome the flow execution outcome + * @param request the current request + * @param response the current response + */ + protected ModelAndView defaultHandleExecutionOutcome(String flowId, FlowExecutionOutcome outcome, HttpServletRequest request, HttpServletResponse response) throws IOException { if (!response.isCommitted()) { // by default, just start the flow over passing the output as input @@ -174,7 +235,17 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H return null; } - protected ModelAndView defaultHandleFlowException(String flowId, FlowException e, HttpServletRequest request, + /** + * The default algorithm for handling a {@link FlowException} now handled by the Web Flow system. Only called if + * {@link FlowHandler#handleException(FlowException, HttpServletRequest, HttpServletResponse)} returns null. This + * implementation rethrows the exception unless it is a {@link NoSuchFlowExecutionException}. If the exception is a + * NoSuchFlowExecutionException, this implementation attempts to start a new execution of the ended or expired flow. + * @param flowId the id of the ended flow + * @param e the flow exception + * @param request the current request + * @param response the current response + */ + protected ModelAndView defaultHandleException(String flowId, FlowException e, HttpServletRequest request, HttpServletResponse response) throws IOException { if (e instanceof NoSuchFlowExecutionException && flowId != null) { if (!response.isCommitted()) { @@ -194,15 +265,15 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H private ModelAndView handleFlowExecutionResult(FlowExecutionResult result, ServletExternalContext context, HttpServletRequest request, HttpServletResponse response, FlowHandler handler) throws IOException { - if (result.paused()) { - if (context.flowExecutionRedirectRequested()) { + if (result.isPaused()) { + if (context.getFlowExecutionRedirectRequested()) { String url = urlHandler.createFlowExecutionUrl(result.getFlowId(), result.getPausedKey(), request); if (logger.isDebugEnabled()) { logger.debug("Sending flow execution redirect to " + url); } sendRedirect(context, request, response, url); return null; - } else if (context.externalRedirectRequested()) { + } else if (context.getExternalRedirectRequested()) { if (logger.isDebugEnabled()) { logger.debug("Sending external redirect to " + context.getExternalRedirectUrl()); } @@ -211,8 +282,8 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H } else { return null; } - } else if (result.ended()) { - if (context.flowDefinitionRedirectRequested()) { + } else if (result.isEnded()) { + if (context.getFlowDefinitionRedirectRequested()) { String flowId = context.getFlowRedirectFlowId(); AttributeMap input = context.getFlowRedirectFlowInput(); String url = urlHandler.createFlowDefinitionUrl(flowId, input, request); @@ -221,7 +292,7 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H } sendRedirect(context, request, response, url); return null; - } else if (context.externalRedirectRequested()) { + } else if (context.getExternalRedirectRequested()) { if (logger.isDebugEnabled()) { logger.debug("Sending external redirect to " + context.getExternalRedirectUrl()); } @@ -229,7 +300,7 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H return null; } else { String location = handler.handleExecutionOutcome(result.getOutcome(), request, response); - return location != null ? createRedirectView(location, request) : defaultHandleFlowOutcome(result + return location != null ? createRedirectView(location, request) : defaultHandleExecutionOutcome(result .getFlowId(), result.getOutcome(), request, response); } } else { @@ -238,20 +309,35 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H } private ModelAndView createRedirectView(String location, HttpServletRequest request) { - if (location.startsWith("/")) { - return new ModelAndView(new RedirectView(location, true)); + if (location.startsWith("servletPath:")) { + return createServletRelativeRedirect(location.substring("servletPath:".length()), request); + } else if (location.startsWith("contextPath:")) { + String contextUrl = location.substring("contextPath:".length()); + if (!contextUrl.startsWith("/")) { + contextUrl = "/" + contextUrl; + } + return new ModelAndView(new RedirectView(contextUrl, true)); + } else if (location.startsWith("redirectUrl:")) { + return new ModelAndView(new RedirectView(location.substring("redirectUrl:".length()))); } else { - StringBuffer url = new StringBuffer(request.getServletPath()); - url.append('/'); - url.append(location); - return new ModelAndView(new RedirectView(url.toString(), true)); + return createServletRelativeRedirect(location, request); } } + private ModelAndView createServletRelativeRedirect(String location, HttpServletRequest request) { + StringBuffer url = new StringBuffer(request.getServletPath()); + if (!location.startsWith("/")) { + url.append('/'); + } + url.append(location); + return new ModelAndView(new RedirectView(url.toString(), true)); + } + private void sendRedirect(ServletExternalContext context, HttpServletRequest request, HttpServletResponse response, String targetUrl) throws IOException { if (context.isAjaxRequest()) { - ajaxHandler.sendAjaxRedirect(getServletContext(), request, response, targetUrl, context.isAjaxRequest()); + ajaxHandler.sendAjaxRedirect(getServletContext(), request, response, targetUrl, context + .getRedirectInPopup()); } else if (!response.isCommitted()) { response.sendRedirect(response.encodeRedirectURL(targetUrl)); } @@ -260,7 +346,7 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H private ModelAndView handleFlowException(FlowException e, HttpServletRequest request, HttpServletResponse response, FlowHandler handler) throws IOException { String location = handler.handleException(e, request, response); - return location != null ? createRedirectView(location, request) : defaultHandleFlowException(getFlowId(handler, + return location != null ? createRedirectView(location, request) : defaultHandleException(getFlowId(handler, request), e, request, response); } @@ -273,7 +359,7 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H if (flowId != null) { return flowId; } else { - return urlHandler.getFlowId(request); + return defaultGetFlowId(request); } } @@ -282,7 +368,7 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H if (input != null) { return input; } else { - return defaultFlowExecutionInputMap(request); + return defaultCreateFlowExecutionInputMap(request); } } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java index df1f1fb4..055825ba 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java @@ -149,7 +149,8 @@ public class MockExternalContext implements ExternalContext { } public boolean isResponseCommitted() { - return flowExecutionRedirectRequested() || flowDefinitionRedirectRequested() || externalRedirectRequested(); + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); } public boolean isResponseAllowed() { @@ -318,19 +319,19 @@ public class MockExternalContext implements ExternalContext { /** * Returns the flag indicating if a flow execution redirect response has been requested by the flow. */ - public boolean flowExecutionRedirectRequested() { + public boolean getFlowExecutionRedirectRequested() { return flowExecutionRedirectRequested; } /** * Returns the flag indicating if a flow definition redirect response has been requested by the flow. */ - public boolean flowDefinitionRedirectRequested() { + public boolean getFlowDefinitionRedirectRequested() { return flowDefinitionRedirectFlowId != null; } /** - * Returns the id of the flow definition to redirect to. Only set when {@link #flowDefinitionRedirectRequested()} + * Returns the id of the flow definition to redirect to. Only set when {@link #getFlowDefinitionRedirectRequested()} * returns true. */ public String getFlowRedirectFlowId() { @@ -339,7 +340,7 @@ public class MockExternalContext implements ExternalContext { /** * Returns the input to pass the flow definition through the redirect. Only set when - * {@link #flowDefinitionRedirectRequested()} returns true. + * {@link #getFlowDefinitionRedirectRequested()} returns true. */ public AttributeMap getFlowRedirectFlowInput() { return flowDefinitionRedirectFlowInput; @@ -348,12 +349,12 @@ public class MockExternalContext implements ExternalContext { /** * Returns the flag indicating if an external redirect response has been requested by the flow. */ - public boolean externalRedirectRequested() { + public boolean getExternalRedirectRequested() { return externalRedirectUrl != null; } /** - * Returns the URL to redirect to. Only set if {@link #externalRedirectRequested()} returns true. + * Returns the URL to redirect to. Only set if {@link #getExternalRedirectRequested()} returns true. */ public String getExternalRedirectUrl() { return externalRedirectUrl; @@ -362,7 +363,7 @@ public class MockExternalContext implements ExternalContext { /** * If a redirect response has been requested, indicates if the redirect should be issued from a popup dialog. */ - public boolean redirectInPopup() { + public boolean getRedirectInPopup() { return redirectInPopup; } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java b/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java index 62cccfbc..929ecb53 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java @@ -74,20 +74,20 @@ public class PortletExternalContextTests extends TestCase { public void testCommitExecutionRedirect() { context.requestFlowExecutionRedirect(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowExecutionRedirectRequested()); + assertTrue(context.getFlowExecutionRedirectRequested()); } public void testCommitFlowRedirect() { context.requestFlowDefinitionRedirect("foo", null); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowDefinitionRedirectRequested()); + assertTrue(context.getFlowDefinitionRedirectRequested()); assertEquals("foo", context.getFlowRedirectFlowId()); } public void testCommitExternalRedirect() { context.requestExternalRedirect("foo"); assertTrue(context.isResponseCommitted()); - assertTrue(context.externalRedirectRequested()); + assertTrue(context.getExternalRedirectRequested()); assertEquals("foo", context.getExternalRedirectUrl()); } @@ -95,26 +95,26 @@ public class PortletExternalContextTests extends TestCase { context.requestFlowExecutionRedirect(); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowExecutionRedirectRequested()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getFlowExecutionRedirectRequested()); + assertTrue(context.getRedirectInPopup()); } public void testCommitFlowRedirectPopup() { context.requestFlowDefinitionRedirect("foo", null); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowDefinitionRedirectRequested()); + assertTrue(context.getFlowDefinitionRedirectRequested()); assertEquals("foo", context.getFlowRedirectFlowId()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getRedirectInPopup()); } public void testCommitExternalRedirectPopup() { context.requestExternalRedirect("foo"); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.externalRedirectRequested()); + assertTrue(context.getExternalRedirectRequested()); assertEquals("foo", context.getExternalRedirectUrl()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getRedirectInPopup()); } public void testResponseAllowed() { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/ServletExternalContextTests.java b/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/ServletExternalContextTests.java index 9a9e9311..42be908d 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/ServletExternalContextTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/context/servlet/ServletExternalContextTests.java @@ -72,20 +72,20 @@ public class ServletExternalContextTests extends TestCase { public void testCommitExecutionRedirect() { context.requestFlowExecutionRedirect(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowExecutionRedirectRequested()); + assertTrue(context.getFlowExecutionRedirectRequested()); } public void testCommitFlowRedirect() { context.requestFlowDefinitionRedirect("foo", null); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowDefinitionRedirectRequested()); + assertTrue(context.getFlowDefinitionRedirectRequested()); assertEquals("foo", context.getFlowRedirectFlowId()); } public void testCommitExternalRedirect() { context.requestExternalRedirect("foo"); assertTrue(context.isResponseCommitted()); - assertTrue(context.externalRedirectRequested()); + assertTrue(context.getExternalRedirectRequested()); assertEquals("foo", context.getExternalRedirectUrl()); } @@ -93,26 +93,26 @@ public class ServletExternalContextTests extends TestCase { context.requestFlowExecutionRedirect(); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowExecutionRedirectRequested()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getFlowExecutionRedirectRequested()); + assertTrue(context.getRedirectInPopup()); } public void testCommitFlowRedirectPopup() { context.requestFlowDefinitionRedirect("foo", null); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.flowDefinitionRedirectRequested()); + assertTrue(context.getFlowDefinitionRedirectRequested()); assertEquals("foo", context.getFlowRedirectFlowId()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getRedirectInPopup()); } public void testCommitExternalRedirectPopup() { context.requestExternalRedirect("foo"); context.requestRedirectInPopup(); assertTrue(context.isResponseCommitted()); - assertTrue(context.externalRedirectRequested()); + assertTrue(context.getExternalRedirectRequested()); assertEquals("foo", context.getExternalRedirectUrl()); - assertTrue(context.redirectInPopup()); + assertTrue(context.getRedirectInPopup()); } public void testResponseAllowed() { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java index 0c72c491..2ecbfff6 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java @@ -68,7 +68,7 @@ public class ViewStateTests extends TestCase { MockRequestControlContext context = new MockRequestControlContext(flow); state.enter(context); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertTrue(context.getMockExternalContext().flowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testEnterViewStateWithNoLocalRedirect() { @@ -79,7 +79,7 @@ public class ViewStateTests extends TestCase { MockRequestControlContext context = new MockRequestControlContext(flow); state.enter(context); assertTrue("Render called", context.getFlowScope().contains("renderCalled")); - assertFalse(context.getMockExternalContext().flowExecutionRedirectRequested()); + assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testEnterViewStateRedirectInPopup() { @@ -91,8 +91,8 @@ public class ViewStateTests extends TestCase { MockRequestControlContext context = new MockRequestControlContext(flow); state.enter(context); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertTrue(context.getMockExternalContext().flowExecutionRedirectRequested()); - assertTrue(context.getMockExternalContext().redirectInPopup()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getRedirectInPopup()); } public void testEnterViewStateWithAlwaysRedirectOnPause() { @@ -103,7 +103,7 @@ public class ViewStateTests extends TestCase { context.setAlwaysRedirectOnPause(true); state.enter(context); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertTrue(context.getMockExternalContext().flowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testEnterViewStateWithPopup() { @@ -115,7 +115,7 @@ public class ViewStateTests extends TestCase { context.setAlwaysRedirectOnPause(true); state.enter(context); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertTrue(context.getMockExternalContext().flowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testResumeViewStateForRefresh() { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/FlowExecutorImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/FlowExecutorImplTests.java index cfc63efe..65c556ef 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/executor/FlowExecutorImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/FlowExecutorImplTests.java @@ -62,9 +62,9 @@ public class FlowExecutorImplTests extends TestCase { replayMocks(); FlowExecutionResult result = flowExecutor.launchExecution("foo", null, context); - assertTrue(result.paused()); + assertTrue(result.isPaused()); assertEquals("12345", result.getPausedKey()); - assertFalse(result.ended()); + assertFalse(result.isEnded()); assertNull(result.getOutcome()); assertNull(ExternalContextHolder.getExternalContext()); verifyMocks(); @@ -90,10 +90,10 @@ public class FlowExecutorImplTests extends TestCase { replayMocks(); FlowExecutionResult result = flowExecutor.launchExecution("foo", null, context); - assertTrue(result.ended()); + assertTrue(result.isEnded()); assertEquals("finish", result.getOutcome().getId()); assertTrue(result.getOutcome().getOutput().isEmpty()); - assertFalse(result.paused()); + assertFalse(result.isPaused()); assertNull(result.getPausedKey()); assertNull(ExternalContextHolder.getExternalContext()); verifyMocks(); @@ -127,9 +127,9 @@ public class FlowExecutorImplTests extends TestCase { FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context); verifyMocks(); - assertTrue(result.paused()); + assertTrue(result.isPaused()); assertEquals("12345", result.getPausedKey()); - assertFalse(result.ended()); + assertFalse(result.isEnded()); assertNull(result.getOutcome()); assertNull(ExternalContextHolder.getExternalContext()); verifyMocks(); @@ -166,10 +166,10 @@ public class FlowExecutorImplTests extends TestCase { replayMocks(); FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context); - assertTrue(result.ended()); + assertTrue(result.isEnded()); assertEquals("finish", result.getOutcome().getId()); assertEquals(output, result.getOutcome().getOutput()); - assertFalse(result.paused()); + assertFalse(result.isPaused()); assertNull(result.getPausedKey()); assertNull(ExternalContextHolder.getExternalContext()); verifyMocks(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowControllerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowControllerTests.java index 0276b59b..a43b55f9 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowControllerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowControllerTests.java @@ -28,25 +28,33 @@ import org.springframework.webflow.test.MockFlowExecutionKey; public class FlowControllerTests extends TestCase { private FlowController controller; private FlowExecutor executor; - private MockServletContext servletContext; private MockHttpServletRequest request; private MockHttpServletResponse response; private ServletExternalContext context; - protected void setUp() { + protected void setUp() throws Exception { executor = (FlowExecutor) EasyMock.createMock(FlowExecutor.class); - controller = new FlowController(executor) { + controller = new FlowController(); + FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter() { protected ServletExternalContext createServletExternalContext(HttpServletRequest request, HttpServletResponse response) { return context; } }; - servletContext = new MockServletContext(); + handlerAdapter.setFlowExecutor(executor); + StaticWebApplicationContext applicationContext = new StaticWebApplicationContext(); + MockServletContext servletContext = new MockServletContext(); + applicationContext.setServletContext(servletContext); + handlerAdapter.setApplicationContext(applicationContext); + handlerAdapter.afterPropertiesSet(); + + controller.setFlowHandlerAdapter(handlerAdapter); + controller.setApplicationContext(new StaticWebApplicationContext()); + controller.afterPropertiesSet(); + request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); context = new ServletExternalContext(servletContext, request, response, controller.getFlowUrlHandler()); - controller.setApplicationContext(new StaticWebApplicationContext()); - controller.setServletContext(servletContext); } public void testLaunchFlowRequest() throws Exception { @@ -55,9 +63,7 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); @@ -72,9 +78,7 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); @@ -133,10 +137,8 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); context.requestFlowExecutionRedirect(); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); @@ -153,12 +155,10 @@ public class FlowControllerTests extends TestCase { request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); request.addHeader("Accept", "text/html;type=ajax"); - Map parameters = new HashMap(); - request.setParameters(parameters); context.setAjaxRequest(true); context.requestFlowExecutionRedirect(); context.requestRedirectInPopup(); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); @@ -201,12 +201,10 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); LocalAttributeMap input = new LocalAttributeMap(); input.put("baz", "boop"); context.requestFlowDefinitionRedirect("bar", input); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); @@ -226,10 +224,8 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); context.requestExternalRedirect("http://www.paypal.com"); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); @@ -246,9 +242,7 @@ public class FlowControllerTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); - executor.launchExecution("foo", new LocalAttributeMap(parameters), context); + executor.launchExecution("foo", null, context); FlowException flowException = new FlowException("Error") { }; EasyMock.expectLastCall().andThrow(flowException); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapterTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapterTests.java index 9fc1f948..a883cc56 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapterTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/servlet/FlowHandlerAdapterTests.java @@ -25,9 +25,8 @@ import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.test.MockFlowExecutionKey; public class FlowHandlerAdapterTests extends TestCase { - private FlowHandlerAdapter controller; - private FlowExecutor executor; - private MockServletContext servletContext; + private FlowHandlerAdapter flowHandlerAdapter; + private FlowExecutor flowExecutor; private MockHttpServletRequest request; private MockHttpServletResponse response; private ServletExternalContext context; @@ -36,20 +35,21 @@ public class FlowHandlerAdapterTests extends TestCase { private boolean handleException; private boolean handleExecutionOutcome; - protected void setUp() { - executor = (FlowExecutor) EasyMock.createMock(FlowExecutor.class); - controller = new FlowHandlerAdapter(executor) { + protected void setUp() throws Exception { + flowExecutor = (FlowExecutor) EasyMock.createMock(FlowExecutor.class); + flowHandlerAdapter = new FlowHandlerAdapter() { protected ServletExternalContext createServletExternalContext(HttpServletRequest request, HttpServletResponse response) { return context; } }; - servletContext = new MockServletContext(); - request = new MockHttpServletRequest(); - response = new MockHttpServletResponse(); - context = new ServletExternalContext(servletContext, request, response, controller.getFlowUrlHandler()); - controller.setApplicationContext(new StaticWebApplicationContext()); - controller.setServletContext(servletContext); + flowHandlerAdapter.setFlowExecutor(flowExecutor); + MockServletContext servletContext = new MockServletContext(); + StaticWebApplicationContext applicationContext = new StaticWebApplicationContext(); + applicationContext.setServletContext(servletContext); + flowHandlerAdapter.setApplicationContext(applicationContext); + flowHandlerAdapter.afterPropertiesSet(); + flowHandler = new FlowHandler() { public MutableAttributeMap createExecutionInputMap(HttpServletRequest request) { assertEquals(FlowHandlerAdapterTests.this.request, request); @@ -76,8 +76,11 @@ public class FlowHandlerAdapterTests extends TestCase { return null; } } - }; + + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + context = new ServletExternalContext(servletContext, request, response, flowHandlerAdapter.getFlowUrlHandler()); } public void testLaunchFlowRequest() throws Exception { @@ -86,13 +89,13 @@ public class FlowHandlerAdapterTests extends TestCase { request.setPathInfo("/whatever"); request.setRequestURI("/springtravel/app/whatever"); request.setMethod("GET"); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testLaunchFlowRequestEndsAfterProcessing() throws Exception { @@ -103,17 +106,17 @@ public class FlowHandlerAdapterTests extends TestCase { request.setMethod("GET"); Map parameters = new HashMap(); request.setParameters(parameters); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); assertEquals("/springtravel/app/foo?bar=baz", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testResumeFlowRequest() throws Exception { @@ -123,15 +126,13 @@ public class FlowHandlerAdapterTests extends TestCase { request.setRequestURI("/springtravel/app/foo"); request.setMethod("POST"); request.addParameter("execution", "12345"); - Map parameters = new HashMap(); - request.setParameters(parameters); - executor.resumeExecution("12345", context); + flowExecutor.resumeExecution("12345", context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "123456"); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testResumeFlowRequestEndsAfterProcessing() throws Exception { @@ -143,17 +144,17 @@ public class FlowHandlerAdapterTests extends TestCase { request.addParameter("execution", "12345"); Map parameters = new HashMap(); request.setParameters(parameters); - executor.resumeExecution("12345", context); + flowExecutor.resumeExecution("12345", context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); assertEquals("/springtravel/app/foo?bar=baz", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testLaunchFlowWithExecutionRedirect() throws Exception { @@ -162,18 +163,16 @@ public class FlowHandlerAdapterTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); context.requestFlowExecutionRedirect(); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); assertEquals("/springtravel/app/foo?execution=12345", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testLaunchFlowWithDefinitionRedirect() throws Exception { @@ -187,18 +186,18 @@ public class FlowHandlerAdapterTests extends TestCase { LocalAttributeMap input = new LocalAttributeMap(); input.put("baz", "boop"); context.requestFlowDefinitionRedirect("bar", input); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); assertEquals("/springtravel/app/bar?baz=boop", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testLaunchFlowWithExternalRedirect() throws Exception { @@ -207,18 +206,16 @@ public class FlowHandlerAdapterTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - Map parameters = new HashMap(); - request.setParameters(parameters); context.requestExternalRedirect("http://www.paypal.com"); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); assertEquals("http://www.paypal.com", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testDefaultHandleFlowException() throws Exception { @@ -229,18 +226,18 @@ public class FlowHandlerAdapterTests extends TestCase { request.setMethod("GET"); Map parameters = new HashMap(); request.setParameters(parameters); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); FlowException flowException = new FlowException("Error") { }; EasyMock.expectLastCall().andThrow(flowException); - EasyMock.replay(new Object[] { executor }); + EasyMock.replay(new Object[] { flowExecutor }); try { - controller.handle(request, response, flowHandler); + flowHandlerAdapter.handle(request, response, flowHandler); fail("Should have thrown exception"); } catch (FlowException e) { assertEquals(flowException, e); } - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testDefaultHandleNoSuchFlowExecutionException() throws Exception { @@ -250,14 +247,14 @@ public class FlowHandlerAdapterTests extends TestCase { request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); request.addParameter("execution", "12345"); - executor.resumeExecution("12345", context); + flowExecutor.resumeExecution("12345", context); FlowException flowException = new NoSuchFlowExecutionException(new MockFlowExecutionKey("12345"), null); EasyMock.expectLastCall().andThrow(flowException); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNull(mv); assertEquals("/springtravel/app/foo", response.getRedirectedUrl()); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testHandleFlowOutcomeCustomFlowHandler() throws Exception { @@ -267,16 +264,16 @@ public class FlowHandlerAdapterTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNotNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } public void testHandleFlowExceptionCustomFlowHandler() throws Exception { @@ -288,11 +285,11 @@ public class FlowHandlerAdapterTests extends TestCase { request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); - executor.launchExecution("foo", flowInput, context); + flowExecutor.launchExecution("foo", flowInput, context); EasyMock.expectLastCall().andThrow(flowException); - EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handle(request, response, flowHandler); + EasyMock.replay(new Object[] { flowExecutor }); + ModelAndView mv = flowHandlerAdapter.handle(request, response, flowHandler); assertNotNull(mv); - EasyMock.verify(new Object[] { executor }); + EasyMock.verify(new Object[] { flowExecutor }); } }