elimintated controller/handler adapter duplication

made spring beanish with default constructor
This commit is contained in:
Keith Donald
2008-04-23 16:05:32 +00:00
parent 36655659be
commit 492c9f2246
17 changed files with 345 additions and 422 deletions

View File

@@ -21,7 +21,7 @@
<!-- Handles requests mapped to the Spring Web Flow system -->
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
<constructor-arg ref="flowExecutor" />
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
<!-- Maps logical view names to Facelet templates (e.g. 'search' to '/WEB-INF/search.xhtml' -->

View File

@@ -57,7 +57,7 @@
<!-- Enables FlowHandlers -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<constructor-arg ref="flowExecutor" />
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
</beans>

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 <code>null</code> if this is not an ended result
*/
public FlowExecutionOutcome getOutcome() {

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -58,11 +58,13 @@ public interface FlowHandler {
* <ul>
* <li>servletPath: - the location is relative to the current servlet
* <li>contextPath: - the location is relative to the current web application</li>
* <li>serverPath: - the location is relative to the current server, which may host several applications
* <li>url: - the location is an absolute URI beginning with a scheme like "http://" If the location string
* <li>redirectUrl: - the location is an URL to pass in unchanged to
* {@link HttpServletResponse#sendRedirect(String)}.
* </ul>
* 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
* <p>
* For servlet-relative and context-relative URLs, a leading slash is optional.
*
* @param outcome the outcome that was reached
* @param request the current request

View File

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

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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);

View File

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