diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java index 103a8b4a..36bac744 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java @@ -22,6 +22,7 @@ import org.springframework.util.ClassUtils; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceView; import org.springframework.web.servlet.view.JstlView; +import org.springframework.webflow.core.collection.ParameterMap; import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.Event; @@ -163,24 +164,28 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon private org.springframework.web.servlet.View view; + private String eventId; + public MvcView(org.springframework.web.servlet.View view, RequestContext context) { this.view = view; this.context = context; } public boolean eventSignaled() { - return context.getRequestParameters().contains("_eventId"); + determineEventId(context); + return eventId != null; } public Event getEvent() { - return new Event(view, context.getRequestParameters().get("_eventId"), context.getRequestParameters() - .asAttributeMap()); + return new Event(this, eventId, context.getRequestParameters().asAttributeMap()); } public void render() { Map model = new HashMap(); model.putAll(context.getConversationScope().union(context.getFlowScope()).union(context.getFlashScope()) .union(context.getRequestScope()).asMap()); + model.put("flowExecutionRequestContext", context); + model.put("flowExecutionUrl", context.getFlowExecutionUrl()); try { view.render(model, (HttpServletRequest) context.getExternalContext().getRequest(), (HttpServletResponse) context.getExternalContext().getResponse()); @@ -188,6 +193,54 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon throw new IllegalStateException("Exception rendering view", e); } } + + private void determineEventId(RequestContext context) { + eventId = findParameter("_eventId", context.getRequestParameters()); + } + + /** + * Obtain a named parameter from the request parameters. This method will try to obtain a parameter value using + * the following algorithm: + *
null if the parameter does not exist in given request
+ */
+ private String findParameter(String logicalParameterName, ParameterMap parameters) {
+ // first try to get it as a normal name=value parameter
+ String value = parameters.get(logicalParameterName);
+ if (value != null) {
+ return value;
+ }
+ // if no value yet, try to get it as a name_value=xyz parameter
+ String prefix = logicalParameterName + "_";
+ Iterator paramNames = parameters.asMap().keySet().iterator();
+ while (paramNames.hasNext()) {
+ String paramName = (String) paramNames.next();
+ if (paramName.startsWith(prefix)) {
+ String strValue = paramName.substring(prefix.length());
+ // support images buttons, which would submit parameters as
+ // name_value.x=123
+ if (strValue.endsWith(".x") || strValue.endsWith(".y")) {
+ strValue = strValue.substring(0, strValue.length() - 2);
+ }
+ return strValue;
+ }
+ }
+ // we couldn't find the parameter value
+ return null;
+ }
+
}
/**
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/MvcViewFactoryTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/MvcViewFactoryTests.java
index 1b26bf96..1f623084 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/MvcViewFactoryTests.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/MvcViewFactoryTests.java
@@ -21,6 +21,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.ClassUtils;
import org.springframework.web.servlet.ViewResolver;
+import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.test.MockExternalContext;
@@ -56,6 +57,7 @@ public class MvcViewFactoryTests extends TestCase {
externalContext.setResponse(response);
context.setExternalContext(externalContext);
View view = viewFactory.getView(context);
+ assertEquals(false, view.eventSignaled());
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
@@ -74,10 +76,71 @@ public class MvcViewFactoryTests extends TestCase {
externalContext.setResponse(response);
context.setExternalContext(externalContext);
View view = viewFactory.getView(context);
+ assertEquals(false, view.eventSignaled());
view.render();
assertEquals("myview", response.getForwardedUrl());
}
+ public void testRestoreView() {
+ creator.setApplicationContext(context);
+ ResourceLoader viewResourceLoader = new ResourceLoader() {
+ public ClassLoader getClassLoader() {
+ return ClassUtils.getDefaultClassLoader();
+ }
+
+ public Resource getResource(String name) {
+ return new TestContextResource("/parent/" + name);
+ }
+ };
+ Expression viewId = new StaticExpression("myview.jsp");
+ ViewFactory viewFactory = creator.createViewFactory(viewId, viewResourceLoader);
+ MockRequestContext context = new MockRequestContext();
+ MockExternalContext externalContext = new MockExternalContext();
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ externalContext.putRequestParameter("_eventId", "foo");
+ externalContext.setRequest(request);
+ externalContext.setResponse(response);
+ context.setExternalContext(externalContext);
+ View view = viewFactory.getView(context);
+ assertEquals(true, view.eventSignaled());
+ Event e = view.getEvent();
+ assertEquals(view, e.getSource());
+ assertEquals("foo", e.getId());
+ view.render();
+ assertEquals("/parent/myview.jsp", response.getForwardedUrl());
+ }
+
+ public void testRestoreViewButtonEventIdFormat() {
+ creator.setApplicationContext(context);
+ ResourceLoader viewResourceLoader = new ResourceLoader() {
+ public ClassLoader getClassLoader() {
+ return ClassUtils.getDefaultClassLoader();
+ }
+
+ public Resource getResource(String name) {
+ return new TestContextResource("/parent/" + name);
+ }
+ };
+ Expression viewId = new StaticExpression("myview.jsp");
+ ViewFactory viewFactory = creator.createViewFactory(viewId, viewResourceLoader);
+ MockRequestContext context = new MockRequestContext();
+ MockExternalContext externalContext = new MockExternalContext();
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ externalContext.putRequestParameter("_eventId_foo", "true");
+ externalContext.setRequest(request);
+ externalContext.setResponse(response);
+ context.setExternalContext(externalContext);
+ View view = viewFactory.getView(context);
+ assertEquals(true, view.eventSignaled());
+ Event e = view.getEvent();
+ assertEquals(view, e.getSource());
+ assertEquals("foo", e.getId());
+ view.render();
+ assertEquals("/parent/myview.jsp", response.getForwardedUrl());
+ }
+
private static class MockViewResolver implements ViewResolver {
private String expectedViewName;