flow handler simplification

This commit is contained in:
Keith Donald
2008-04-11 20:26:35 +00:00
parent 9f2b408101
commit 477c9e335f
18 changed files with 68 additions and 51 deletions

View File

@@ -3,14 +3,12 @@ package org.springframework.webflow.samples.booking;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.mvc.servlet.AbstractFlowHandler;
public class BookingFlowHandler extends AbstractFlowHandler {
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
return new ModelAndView(new RedirectView("/spring/hotels/index", true));
return "/spring/hotels/index";
}
}

View File

@@ -99,7 +99,7 @@ public interface ExternalContext {
* @param flowExecutionKey the flow execution key
* @return the flow execution URL
*/
public String getFlowExecutionUri(String flowId, String flowExecutionKey);
public String getFlowExecutionUrl(String flowId, String flowExecutionKey);
/**
* Provides access to the user's principal security object.

View File

@@ -50,6 +50,13 @@ public interface FlowUrlHandler {
*/
public void setFlowExecutionInSession(String flowExecutionKey, RenderRequest request);
/**
* Creates a flow execution URL suitable for use as an action URL.
* @param flowId the flow id
* @param flowExecutionKey the flow execution key
* @param response the render response
* @return the execution url
*/
public String createFlowExecutionUrl(String flowId, String flowExecutionKey, RenderResponse response);
}

View File

@@ -175,7 +175,7 @@ public class PortletExternalContext implements ExternalContext {
return false;
}
public String getFlowExecutionUri(String flowId, String flowExecutionKey) {
public String getFlowExecutionUrl(String flowId, String flowExecutionKey) {
if (this.isRenderPhase()) {
return flowUrlHandler.createFlowExecutionUrl(flowId, flowExecutionKey, (RenderResponse) response);
} else {

View File

@@ -191,7 +191,7 @@ public class ServletExternalContext implements ExternalContext {
return ajaxRequest;
}
public String getFlowExecutionUri(String flowId, String flowExecutionKey) {
public String getFlowExecutionUrl(String flowId, String flowExecutionKey) {
return flowUrlHandler.createFlowExecutionUrl(flowId, flowExecutionKey, request);
}

View File

@@ -174,7 +174,7 @@ class RequestControlContextImpl implements RequestControlContext {
public String getFlowExecutionUrl() {
String key = flowExecution.getKey() != null ? flowExecution.getKey().toString() : null;
if (key != null) {
return externalContext.getFlowExecutionUri(flowExecution.getDefinition().getId(), key);
return externalContext.getFlowExecutionUrl(flowExecution.getDefinition().getId(), key);
} else {
return null;
}

View File

@@ -29,8 +29,7 @@ public class AbstractFlowHandler implements FlowHandler {
return null;
}
public ModelAndView handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request,
RenderResponse response) {
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request, RenderResponse response) {
return null;
}

View File

@@ -58,10 +58,10 @@ public interface FlowHandler {
* @param output the output returned by the flow execution
* @param request the current render request
* @param response the current render response
* @return the model and view to render on the occurrence of this outcome, or null if the outcome was not handled
* @return the id of the flow to start after handling the outcome, or null if the outcome should be handled by the
* caller
*/
public ModelAndView handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request,
RenderResponse response);
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request, RenderResponse response);
/**
* Handles a flow exception that was not handled by the Web Flow system. Used by a Controller to handle a specific

View File

@@ -75,8 +75,8 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen
session.removeAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE);
String outcome = result.getEndedOutcome();
AttributeMap output = result.getEndedOutput();
ModelAndView mv = flowHandler.handleFlowOutcome(outcome, output, request, response);
return mv != null ? mv : defaultHandleFlowOutcome(flowHandler, outcome, output, request, response);
String flowId = flowHandler.handleFlowOutcome(outcome, output, request, response);
return defaultHandleFlowOutcome(flowHandler, outcome, output, flowId, request, response);
} else {
return startFlow(request, response, flowHandler);
}
@@ -131,14 +131,15 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen
}
protected ModelAndView defaultHandleFlowOutcome(FlowHandler flowHandler, String outcome, AttributeMap output,
RenderRequest request, RenderResponse response) throws IOException {
// by default, just start the flow over passing the output as input
String flowId = flowHandler.getFlowId();
String nextFlowId, RenderRequest request, RenderResponse response) throws IOException {
if (nextFlowId == null) {
nextFlowId = flowHandler.getFlowId();
}
if (logger.isDebugEnabled()) {
logger.debug("Restarting a new execution of ended flow '" + flowId + "'");
logger.debug("Starting a new execution of flow '" + nextFlowId + "'");
}
PortletExternalContext context = createPortletExternalContext(request, response);
flowExecutor.launchExecution(flowId, new LocalAttributeMap(output.asMap()), context);
flowExecutor.launchExecution(nextFlowId, new LocalAttributeMap(output.asMap()), context);
return null;
}

View File

@@ -24,13 +24,13 @@ public class AbstractFlowHandler implements FlowHandler {
return null;
}
public ModelAndView handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) {
return null;
}
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
return null;
}
public ModelAndView handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) {
return null;
}
}

View File

@@ -27,6 +27,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;
@@ -268,13 +269,18 @@ public class FlowController extends AbstractController {
HttpServletRequest request, HttpServletResponse response) throws IOException {
FlowHandler handler = getFlowHandler(flowId);
if (handler != null) {
ModelAndView result = handler.handleExecutionOutcome(outcome, endedOutput, request, response);
return result != null ? result : defaultHandleFlowOutcome(flowId, outcome, endedOutput, request, response);
String location = handler.handleExecutionOutcome(outcome, endedOutput, request, response);
return location != null ? createRedirectView(location) : defaultHandleFlowOutcome(flowId, outcome,
endedOutput, request, response);
} else {
return defaultHandleFlowOutcome(flowId, outcome, endedOutput, request, response);
}
}
private ModelAndView createRedirectView(String location) {
return new ModelAndView(new RedirectView(location, true));
}
private ModelAndView handleFlowException(FlowException e, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String flowId = urlHandler.getFlowId(request);

View File

@@ -52,15 +52,16 @@ public interface FlowHandler {
public MutableAttributeMap createExecutionInputMap(HttpServletRequest request);
/**
* Handles a specific flow execution outcome. Used by a Controller to select a new view to render after the flow
* ends.
* Handles a specific flow execution outcome. Used by a Controller to get the location of the resource to redirect
* to after the outcome is handled.
* @param outcome the outcome that was reached
* @param output the output returned by the flow execution
* @param request the current request
* @param response the current response
* @return the model and view to render on the occurrence of this outcome, or null if the outcome was not handled
* @return the location of the new resource to redirect to, or null if the execution outcome was not handled and
* should be handled by the caller
*/
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response);
/**
@@ -70,7 +71,8 @@ public interface FlowHandler {
* the flow executor system if no execution could be restored.
* @param request the current request
* @param response the current response
* @return the model and view to render on the occurrence of this exception, or null if the exception is not handled
* @return the model and view to render on the occurrence of this exception, or null if the exception was not
* handled and should be handled by the caller
*/
public ModelAndView handleException(FlowException e, HttpServletRequest request, HttpServletResponse response);
}

View File

@@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
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;
@@ -224,16 +225,20 @@ public class FlowHandlerAdapter extends WebApplicationObjectSupport implements H
sendRedirect(context, request, response, context.getExternalRedirectUrl());
return null;
} else {
ModelAndView mv = handler.handleExecutionOutcome(result.getEndedOutcome(), result.getEndedOutput(),
String location = handler.handleExecutionOutcome(result.getEndedOutcome(), result.getEndedOutput(),
request, response);
return mv != null ? mv : defaultHandleFlowOutcome(result.getFlowId(), result.getEndedOutcome(), result
.getEndedOutput(), request, response);
return location != null ? createRedirectView(location) : defaultHandleFlowOutcome(result.getFlowId(),
result.getEndedOutcome(), result.getEndedOutput(), request, response);
}
} else {
throw new IllegalStateException("Execution result should have been one of [paused] or [ended]");
}
}
private ModelAndView createRedirectView(String location) {
return new ModelAndView(new RedirectView(location, true));
}
private void sendRedirect(ServletExternalContext context, HttpServletRequest request, HttpServletResponse response,
String targetUrl) throws IOException {
if (context.isAjaxRequest()) {

View File

@@ -133,7 +133,7 @@ public class MockExternalContext implements ExternalContext {
return ajaxRequest;
}
public String getFlowExecutionUri(String flowId, String flowExecutionKey) {
public String getFlowExecutionUrl(String flowId, String flowExecutionKey) {
return "/" + flowId + "?execution=" + flowExecutionKey;
}

View File

@@ -180,7 +180,7 @@ public class MockRequestContext implements RequestContext {
"Flow execution key not yet assigned; unable to build the flow execution url");
} else {
String flowDefinitionId = flowExecutionContext.getDefinition().getId();
return externalContext.getFlowExecutionUri(flowDefinitionId, flowExecutionContext.getKey().toString());
return externalContext.getFlowExecutionUrl(flowDefinitionId, flowExecutionContext.getKey().toString());
}
}

View File

@@ -85,10 +85,10 @@ public class FlowHandlerAdapterTests extends TestCase {
}
}
public ModelAndView handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request,
public String handleFlowOutcome(String outcome, AttributeMap output, RenderRequest request,
RenderResponse response) {
if (handleExecutionOutcome) {
return new ModelAndView("redirect:/home");
return "home";
} else {
return null;
}
@@ -172,16 +172,19 @@ public class FlowHandlerAdapterTests extends TestCase {
public void testHandleFlowOutcomeCustomFlowHandler() throws Exception {
handleExecutionOutcome = true;
renderRequest.setContextPath("/springtravel");
executor.launchExecution("foo", flowInput, renderContext);
LocalAttributeMap output = new LocalAttributeMap();
output.put("bar", "baz");
Event outcome = new Event(this, "finish", output);
FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome);
PortletSession session = renderRequest.getPortletSession();
session.setAttribute("flowExecutionResult", result);
executor.launchExecution("home", flowInput, renderContext);
EasyMock.expectLastCall().andReturn(FlowExecutionResult.createEndedResult("bar", outcome));
EasyMock.replay(new Object[] { executor });
ModelAndView mv = controller.handleRender(renderRequest, renderResponse, flowHandler);
assertNotNull(mv);
assertEquals("redirect:/home", mv.getViewName());
assertNull(mv);
EasyMock.verify(new Object[] { executor });
}
public void testHandleFlowExceptionCustomFlowHandler() throws Exception {

View File

@@ -23,8 +23,6 @@ import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.mvc.servlet.FlowController;
import org.springframework.webflow.mvc.servlet.FlowHandler;
import org.springframework.webflow.test.MockFlowExecutionKey;
public class FlowControllerTests extends TestCase {
@@ -291,7 +289,7 @@ public class FlowControllerTests extends TestCase {
return input;
}
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
return null;
}
@@ -327,7 +325,7 @@ public class FlowControllerTests extends TestCase {
return input;
}
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
assertEquals("finish", outcome);
assertEquals("baz", output.get("bar"));
@@ -372,7 +370,7 @@ public class FlowControllerTests extends TestCase {
return null;
}
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
return null;
}

View File

@@ -23,8 +23,6 @@ import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import org.springframework.webflow.executor.FlowExecutionResult;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.mvc.servlet.FlowHandler;
import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter;
import org.springframework.webflow.test.MockFlowExecutionKey;
public class FlowHandlerAdapterTests extends TestCase {
@@ -72,10 +70,10 @@ public class FlowHandlerAdapterTests extends TestCase {
}
}
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request,
HttpServletResponse response) {
if (handleExecutionOutcome) {
return new ModelAndView("redirect:/home");
return "/home";
} else {
return null;
}