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 @@
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 {
*
+ * 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 }); } }