diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java
index fc41b3b6..751af240 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java
@@ -16,6 +16,7 @@
package org.springframework.webflow.executor.mvc;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import javax.portlet.ActionRequest;
@@ -45,23 +46,23 @@ import org.springframework.webflow.executor.support.ResponseInstructionHandler;
* Point of integration between Spring Portlet MVC and Spring Web Flow: a {@link Controller} that routes incoming
* portlet requests to one or more managed flow executions.
*
- * Requests into the web flow system are handled by a {@link FlowExecutor}, which this class delegates to. Consult
- * the JavaDoc of that class for more information on how requests are processed.
+ * Requests into the web flow system are handled by a {@link FlowExecutor}, which this class delegates to. Consult the
+ * JavaDoc of that class for more information on how requests are processed.
*
* Note: a single PortletFlowController may execute all flows within your application. See the
- * phonebook-portlet sample application for examples of the various strategies for launching and
- * resuming flow executions in a Portlet environment.
+ * phonebook-portlet sample application for examples of the various strategies for launching and resuming
+ * flow executions in a Portlet environment.
*
- * It is also possible to customize the {@link FlowExecutorArgumentHandler} strategy to allow for different types
- * of controller parameterization, for example perhaps in conjunction with a REST-style request mapper.
+ * It is also possible to customize the {@link FlowExecutorArgumentHandler} strategy to allow for different types of
+ * controller parameterization, for example perhaps in conjunction with a REST-style request mapper.
*
* Integrating Spring Web Flow into a Portlet environment puts some minor contraints on your flows. These constraints
* result from technical limitations in the Portlet API, for instance the fact that a render request cannot issue a
* redirect. Keep the following in mind when developing Portlets using Spring Web Flow:
*
* - Using the well known POST-REDIRECT-GET idiom, for instance using alwaysRedirectOnPause or the
- * "redirect:" view prefix, does not make sense in a Portlet environment where the Portlet container handles this
- * using a seperate render phase. In other words, a {@link FlowExecutionRedirect} is not supportd.
+ * "redirect:" view prefix, does not make sense in a Portlet environment where the Portlet container handles this using
+ * a seperate render phase. In other words, a {@link FlowExecutionRedirect} is not supportd.
* - This controller will launch a new flow execution every time it handles a render request without having
* previously handled an action request (for the same session) or the render request containing a flow execution key.
*
@@ -157,9 +158,7 @@ public class PortletFlowController extends AbstractController implements Initial
protected ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) throws Exception {
PortletExternalContext context = new PortletExternalContext(getPortletContext(), request, response);
-
- // look for a cached response instruction in the session put there
- // by the action request phase
+ // look for a cached response instruction in the session put there by the action request phase
// the response instruction could be an "active application view" rendered
// from a view-state or a "confirmation view" rendered by an end-state
ResponseInstruction responseInstruction = extractActionResponseInstruction(request);
@@ -188,10 +187,8 @@ public class PortletFlowController extends AbstractController implements Initial
final PortletExternalContext context = new PortletExternalContext(getPortletContext(), request, response);
final String flowExecutionKey = argumentHandler.extractFlowExecutionKey(context);
final String eventId = argumentHandler.extractEventId(context);
-
// signal the event against the flow execution, returning the next response instruction
final ResponseInstruction responseInstruction = flowExecutor.resume(flowExecutionKey, eventId, context);
-
new ResponseInstructionHandler() {
protected void handleApplicationView(ApplicationView view) throws Exception {
// response instruction is a forward to an "application view"
@@ -201,24 +198,28 @@ public class PortletFlowController extends AbstractController implements Initial
// we need to do this because the responseInstruction stored in the session
// below will be removed from the session when the next render request
// extracts it (see extractActionResponseInstruction)
- response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(),
- responseInstruction.getFlowExecutionKey());
+ response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(), responseInstruction
+ .getFlowExecutionKey());
}
// make response instruction available for rendering during the render phase of this portlet request
exposeToRenderPhase(responseInstruction, request);
}
protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception {
- // set flow id render parameter to request that a new flow be
- // launched within this portlet
- response.setRenderParameters(redirect.getExecutionInput());
+ // set flow id render parameter to request that a new flow be launched within this portlet
response.setRenderParameter(argumentHandler.getFlowIdArgumentName(), redirect.getFlowDefinitionId());
+ // expose flow definition input as render parameters as well
+ Iterator it = redirect.getExecutionInput().entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ response.setRenderParameter(convertToString(entry.getKey()), convertToString(entry.getValue()));
+ }
}
protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception {
// is a flow execution redirect: simply expose key parameter to support refresh during render phase
- response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(),
- responseInstruction.getFlowExecutionKey());
+ response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(), responseInstruction
+ .getFlowExecutionKey());
}
protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception {
@@ -231,8 +232,8 @@ public class PortletFlowController extends AbstractController implements Initial
if (responseInstruction.getFlowExecutionContext().isActive()) {
// flow execution is still active
// set the flow execution key render parameter to support browser refresh
- response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(),
- responseInstruction.getFlowExecutionKey());
+ response.setRenderParameter(argumentHandler.getFlowExecutionKeyArgumentName(), responseInstruction
+ .getFlowExecutionKey());
}
// make response instruction available for rendering during the render phase of this portlet request
exposeToRenderPhase(responseInstruction, request);
@@ -240,6 +241,15 @@ public class PortletFlowController extends AbstractController implements Initial
}.handle(responseInstruction);
}
+ /**
+ * Converts the object to a string. Simply returns {@link String#valueOf(Object)} by default.
+ * @param object the object
+ * @return the string-form of the object
+ */
+ protected String convertToString(Object object) {
+ return String.valueOf(object);
+ }
+
// helpers
/**
@@ -248,8 +258,7 @@ public class PortletFlowController extends AbstractController implements Initial
private void exposeToRenderPhase(ResponseInstruction responseInstruction, ActionRequest request) {
// there are 2 reasons why we need to put the ResponseInstruction in the session
// and we can't just rely on flow execution 'refresh' during the portlet render phase:
- // 1 - a ResponseInstruction rendered from an end-state cannot be refreshed
- // ("confirmation view")
+ // 1 - a ResponseInstruction rendered from an end-state cannot be refreshed ("confirmation view")
// 2 - to make the initial contents of request scope available to the view
PortletSession session = request.getPortletSession(false);
Assert.notNull(session, "A PortletSession is required");
@@ -285,8 +294,8 @@ public class PortletFlowController extends AbstractController implements Initial
// forward to a view as part of an active conversation
ApplicationView forward = (ApplicationView) responseInstruction.getViewSelection();
Map model = new HashMap(forward.getModel());
- argumentHandler.exposeFlowExecutionContext(
- responseInstruction.getFlowExecutionKey(), responseInstruction.getFlowExecutionContext(), model);
+ argumentHandler.exposeFlowExecutionContext(responseInstruction.getFlowExecutionKey(), responseInstruction
+ .getFlowExecutionContext(), model);
return new ModelAndView(forward.getViewName(), model);
}
else if (responseInstruction.isNull()) {