From be53f13371c2c4b23293c0bcc936f1befd10d2be Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Mon, 29 Oct 2007 13:57:07 +0000 Subject: [PATCH] mvc --- .../webflow/mvc/MvcViewFactoryCreator.java | 59 ++++++++++++++++- .../webflow/mvc/MvcViewFactoryTests.java | 63 +++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) 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: + *
    + *
  1. Try to get the parameter value using just the given logical name. This handles parameters of the + * form logicalName = value. For normal parameters, e.g. submitted using a hidden HTML form field, + * this will return the requested value.
  2. + *
  3. Try to obtain the parameter value from the parameter name, where the parameter name in the request is of + * the form logicalName_value = xyz with "_" being the configured delimiter. This deals with + * parameter values submitted using an HTML form submit button.
  4. + *
  5. If the value obtained in the previous step has a ".x" or ".y" suffix, remove that. This handles cases + * where the value was submitted using an HTML form image button. In this case the parameter in the request + * would actually be of the form logicalName_value.x = 123.
  6. + *
+ * @param logicalParameterName the logical name of the request parameter + * @param parameters the available parameter map + * @return the value of the parameter, or 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;