This commit is contained in:
Keith Donald
2007-10-29 13:57:07 +00:00
parent 357fd3ab41
commit be53f13371
2 changed files with 119 additions and 3 deletions

View File

@@ -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:
* <ol>
* <li>Try to get the parameter value using just the given <i>logical</i> name. This handles parameters of the
* form <tt>logicalName = value</tt>. For normal parameters, e.g. submitted using a hidden HTML form field,
* this will return the requested value.</li>
* <li>Try to obtain the parameter value from the parameter name, where the parameter name in the request is of
* the form <tt>logicalName_value = xyz</tt> with "_" being the configured delimiter. This deals with
* parameter values submitted using an HTML form submit button.</li>
* <li>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 <tt>logicalName_value.x = 123</tt>. </li>
* </ol>
* @param logicalParameterName the <i>logical</i> name of the request parameter
* @param parameters the available parameter map
* @return the value of the parameter, or <code>null</code> 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;
}
}
/**

View File

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