mvc tests
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user