mvc tests

This commit is contained in:
Keith Donald
2007-10-29 02:19:13 +00:00
parent 96d633b0b4
commit c813626744
3 changed files with 342 additions and 105 deletions

View File

@@ -1,5 +1,7 @@
package org.springframework.webflow.mvc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -8,54 +10,137 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.binding.expression.Expression;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.OrderComparator;
import org.springframework.core.io.ContextResource;
import org.springframework.core.io.ResourceLoader;
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.engine.builder.ViewFactoryCreator;
import org.springframework.webflow.engine.builder.support.ActionInvokingViewFactory;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
public class MvcViewFactoryCreator implements ViewFactoryCreator {
/**
* View factory creator implementation that produces View Factories that create Spring MVC-based views.
*
* This class is used by a flow builder in a Spring MVC environment to configure view factories on flows that render
* Spring MVC-based views.
*
* This class supports rendering views resolved by existing Spring MVC-based resolver infrastructure, or, if no such
* infrastructure is configured, JSP resources relative to the flow definition being built.
*
* @author Keith Donald
*/
public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationContextAware {
private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext");
private List viewResolvers;
private ApplicationContext applicationContext;
public Action createFinalResponseAction(Expression viewId, ResourceLoader viewResourceLoader) {
return new TestAction();
return new ViewFactoryActionAdapter(createViewFactory(viewId, viewResourceLoader));
}
public ViewFactory createViewFactory(Expression viewId, ResourceLoader viewResourceLoader) {
return new ActionInvokingViewFactory(new TestAction());
}
public class TestAction implements Action {
public Event execute(RequestContext context) throws Exception {
System.out.println("Render me...");
return new Event(this, "success");
if (viewResolvers != null) {
return new ViewResolvingMvcViewFactory(viewId, viewResolvers);
} else {
return new InternalFlowResourceMvcViewFactory(viewId, applicationContext, viewResourceLoader);
}
}
private static class MvcViewFactory implements ViewFactory {
private ResourceLoader viewResourceLoader;
public void setApplicationContext(ApplicationContext context) {
initViewResolvers(context);
this.applicationContext = context;
}
private void initViewResolvers(ApplicationContext context) {
Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
viewResolvers = new ArrayList(matchingBeans.values());
Collections.sort(viewResolvers, new OrderComparator());
}
}
/**
* View factory implementation that creates a Spring-MVC Internal Resource view to render a flow-relative view
* resource such as a JSP or Velocity template.
* @author Keith Donald
*/
static class InternalFlowResourceMvcViewFactory implements ViewFactory {
private Expression viewExpression;
private ApplicationContext applicationContext;
private ResourceLoader resourceLoader;
public InternalFlowResourceMvcViewFactory(Expression viewExpression, ApplicationContext context,
ResourceLoader resourceLoader) {
this.viewExpression = viewExpression;
this.applicationContext = context;
this.resourceLoader = resourceLoader;
}
public View getView(RequestContext context) {
String viewId = (String) viewExpression.getValue(context);
if (viewId.startsWith("/")) {
return getViewInternal(viewId, context);
} else {
ContextResource viewResource = (ContextResource) resourceLoader.getResource(viewId);
return getViewInternal(viewResource.getPathWithinContext(), context);
}
}
private View getViewInternal(String viewPath, RequestContext context) {
if (viewPath.endsWith(".jsp")) {
if (jstlPresent) {
JstlView view = new JstlView(viewPath);
view.setApplicationContext(applicationContext);
return new MvcView(view, context);
} else {
InternalResourceView view = new InternalResourceView(viewPath);
view.setApplicationContext(applicationContext);
return new MvcView(view, context);
}
} else {
throw new IllegalArgumentException("Unsupported view type " + viewPath
+ " only types supported are [.jsp]");
}
}
}
/**
* View factory implementation that delegates to the Spring-configured view resolver chain to resolve the Spring MVC
* view implementation to render.
* @author Keith Donald
*/
private static class ViewResolvingMvcViewFactory implements ViewFactory {
private Expression viewId;
private List viewResolvers;
private boolean internalResourceResolverOnly;
public ViewResolvingMvcViewFactory(Expression viewId, List viewResolvers) {
this.viewId = viewId;
this.viewResolvers = viewResolvers;
}
public View getView(RequestContext context) {
String view = (String) viewExpression.getValue(context);
String view = (String) viewId.getValue(context);
return new MvcView(resolveView(view), context);
}
protected org.springframework.web.servlet.View resolveView(String viewName) {
if (internalResourceResolverOnly && !viewName.startsWith("/")) {
viewName = ((ContextResource) viewResourceLoader.getResource(viewName)).getPathWithinContext();
}
for (Iterator it = viewResolvers.iterator(); it.hasNext();) {
ViewResolver viewResolver = (ViewResolver) it.next();
try {
@@ -65,43 +150,61 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator {
return view;
}
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("Exception resolving view with name '" + viewName + "'", e);
}
}
return null;
}
}
private static class MvcView implements View {
private static class MvcView implements View {
private RequestContext context;
private RequestContext context;
private org.springframework.web.servlet.View view;
private org.springframework.web.servlet.View view;
public MvcView(org.springframework.web.servlet.View view, RequestContext context) {
this.view = view;
this.context = context;
}
public MvcView(org.springframework.web.servlet.View view, RequestContext context) {
this.view = view;
this.context = context;
}
public boolean eventSignaled() {
return context.getRequestParameters().contains("_eventId");
}
public boolean eventSignaled() {
return context.getRequestParameters().contains("_eventId");
}
public Event getEvent() {
return new Event(view, context.getRequestParameters().get("_eventId"), context.getRequestParameters()
.asAttributeMap());
}
public Event getEvent() {
return new Event(view, context.getRequestParameters().get("_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());
try {
view.render(model, (HttpServletRequest) context.getExternalContext().getRequest(),
(HttpServletResponse) context.getExternalContext().getResponse());
} catch (Exception e) {
e.printStackTrace();
}
public void render() {
Map model = new HashMap();
model.putAll(context.getConversationScope().union(context.getFlowScope()).union(context.getFlashScope())
.union(context.getRequestScope()).asMap());
try {
view.render(model, (HttpServletRequest) context.getExternalContext().getRequest(),
(HttpServletResponse) context.getExternalContext().getResponse());
} catch (Exception e) {
throw new IllegalStateException("Exception rendering view", e);
}
}
}
}
/**
* Simple adapter that adapts a view factory render cycle to the action interface.
* @author Keith Donald
*/
private static class ViewFactoryActionAdapter implements Action {
private ViewFactory viewFactory;
public ViewFactoryActionAdapter(ViewFactory viewFactory) {
this.viewFactory = viewFactory;
}
public Event execute(RequestContext context) throws Exception {
viewFactory.getView(context).render();
return new Event(this, "success");
}
}
}

View File

@@ -128,6 +128,62 @@ public class MockExternalContext implements ExternalContext {
return applicationMap;
}
public Object getContext() {
return context;
}
public Object getRequest() {
return request;
}
public Object getResponse() {
return response;
}
public PrintWriter getResponseWriter() {
throw new UnsupportedOperationException("Not yet implemented");
}
public String encode(String string) {
return string;
}
public String buildFlowDefinitionUrl(FlowDefinitionRequestInfo requestInfo) {
throw new UnsupportedOperationException("Not yet implemented");
}
public String buildFlowExecutionUrl(FlowExecutionRequestInfo requestInfo, boolean contextRelative) {
throw new UnsupportedOperationException("Not yet implemented");
}
public void sendFlowDefinitionRedirect(FlowDefinitionRequestInfo requestInfo) {
this.flowDefinitionRedirectResult = requestInfo;
}
public void sendFlowExecutionRedirect(FlowExecutionRequestInfo requestInfo) {
this.flowExecutionRedirectResult = requestInfo;
}
public void sendExternalRedirect(String resourceUri) {
externalRedirectResult = resourceUri;
}
public void setPausedResult(String flowExecutionKey) {
this.pausedFlowExecutionKeyResult = flowExecutionKey;
}
public void setEndedResult(String flowExecutionKey) {
}
public void setExceptionResult(FlowException e) {
exceptionResult = e;
}
public boolean isResponseCommitted() {
return false;
}
// helper setters
public void setFlowId(String flowId) {
@@ -146,6 +202,18 @@ public class MockExternalContext implements ExternalContext {
this.requestPath = requestPath;
}
public void setContext(Object context) {
this.context = context;
}
public void setRequest(Object request) {
this.request = request;
}
public void setResponse(Object response) {
this.response = response;
}
/**
* Set the request parameter map.
* @see ExternalContext#getRequestParameterMap()
@@ -215,60 +283,6 @@ public class MockExternalContext implements ExternalContext {
getMockRequestParameterMap().put(parameterName, parameterValues);
}
public Object getContext() {
return context;
}
public Object getRequest() {
return request;
}
public Object getResponse() {
return response;
}
public PrintWriter getResponseWriter() {
throw new UnsupportedOperationException("Auto-generated method stub");
}
public String encode(String string) {
return string;
}
public String buildFlowDefinitionUrl(FlowDefinitionRequestInfo requestInfo) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Auto-generated method stub");
}
public String buildFlowExecutionUrl(FlowExecutionRequestInfo requestInfo, boolean contextRelative) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Auto-generated method stub");
}
public void sendFlowDefinitionRedirect(FlowDefinitionRequestInfo requestInfo) {
this.flowDefinitionRedirectResult = requestInfo;
}
public void sendFlowExecutionRedirect(FlowExecutionRequestInfo requestInfo) {
this.flowExecutionRedirectResult = requestInfo;
}
public void sendExternalRedirect(String resourceUri) {
externalRedirectResult = resourceUri;
}
public void setPausedResult(String flowExecutionKey) {
this.pausedFlowExecutionKeyResult = flowExecutionKey;
}
public void setEndedResult(String flowExecutionKey) {
}
public void setExceptionResult(FlowException e) {
exceptionResult = e;
}
public FlowDefinitionRequestInfo getFlowDefinitionRedirectResult() {
return flowDefinitionRedirectResult;
}
@@ -288,12 +302,4 @@ public class MockExternalContext implements ExternalContext {
public FlowException getExceptionResult() {
return exceptionResult;
}
public boolean isResponseCommitted() {
return false;
/*
* return flowExecutionRedirectResult == true || flowDefinitionRedirectResult != null || externalRedirectResult !=
* null;
*/
}
}

View File

@@ -0,0 +1,128 @@
package org.springframework.webflow.mvc;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.TestCase;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.support.StaticExpression;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.ContextResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
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.View;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockRequestContext;
public class MvcViewFactoryTests extends TestCase {
private MvcViewFactoryCreator creator;
private StaticApplicationContext context;
protected void setUp() {
creator = new MvcViewFactoryCreator();
context = new StaticApplicationContext();
}
public void testNoResolversGetResource() {
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.setRequest(request);
externalContext.setResponse(response);
context.setExternalContext(externalContext);
View view = viewFactory.getView(context);
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
public void testViewResolversGetResource() {
MockViewResolver viewResolver = new MockViewResolver("myview");
context.getBeanFactory().registerSingleton("viewResolver", viewResolver);
creator.setApplicationContext(context);
Expression viewId = new StaticExpression("myview");
ViewFactory viewFactory = creator.createViewFactory(viewId, null);
MockRequestContext context = new MockRequestContext();
MockExternalContext externalContext = new MockExternalContext();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
externalContext.setRequest(request);
externalContext.setResponse(response);
context.setExternalContext(externalContext);
View view = viewFactory.getView(context);
view.render();
assertEquals("myview", response.getForwardedUrl());
}
private static class MockViewResolver implements ViewResolver {
private String expectedViewName;
public MockViewResolver(String expectedViewName) {
this.expectedViewName = expectedViewName;
}
public org.springframework.web.servlet.View resolveViewName(String viewName, Locale arg1) throws Exception {
assertEquals(expectedViewName, viewName);
return new MockView();
}
class MockView implements org.springframework.web.servlet.View {
boolean renderCalled;
public String getContentType() {
return "text/html";
}
public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
request.getRequestDispatcher(expectedViewName).forward(request, response);
renderCalled = true;
}
}
}
private static class TestContextResource extends AbstractResource implements ContextResource {
private String path;
public TestContextResource(String path) {
this.path = path;
}
public String getDescription() {
return "test context resource";
}
public InputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("Auto-generated method stub");
}
public String getPathWithinContext() {
return path;
}
}
}