From 37dc211f588eeb296a60c8d9f234c8341506ad49 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 26 Jul 2012 03:06:07 +0200 Subject: [PATCH] Support named dispatchers in MockServletContext Currently the getNamedDispatcher(String) method of MockServletContext always returns null. This poses a problem in certain testing scenarios since one would always expect at least a default Servlet to be present. This is specifically important for web application tests that involve the DefaultServletHttpRequestHandler which attempts to forward to the default Servlet after retrieving it by name. Furthermore, there is no way to register a named RequestDispatcher with the MockServletContext. This commit addresses these issues by introducing the following in MockServletContext. - a new defaultServletName property for configuring the name of the default Servlet, which defaults to "default" - named RequestDispatchers can be registered and unregistered - a MockRequestDispatcher is registered for the "default" Servlet automatically in the constructor - when the defaultServletName property is set to a new value the the current default RequestDispatcher is unregistered and replaced with a MockRequestDispatcher for the new defaultServletName Issue: SPR-9587 --- .../mock/web/MockRequestDispatcher.java | 28 +- .../mock/web/MockServletContext.java | 122 +++- .../mock/web/MockRequestDispatcher.java | 28 +- .../mock/web/MockServletContext.java | 126 +++- .../mock/web/MockServletContextTests.java | 86 ++- spring-test/src/test/resources/log4j.xml | 2 +- .../mock/web/MockRequestDispatcher.java | 28 +- .../mock/web/MockServletContext.java | 214 +++++-- .../web/DelegatingServletOutputStream.java | 71 +++ .../mock/web/HeaderValueHolder.java | 96 +++ .../mock/web/MockHttpServletResponse.java | 603 ++++++++++++++++++ .../mock/web/MockRequestDispatcher.java | 93 +++ .../mock/web/MockServletContext.java | 199 +++++- .../mock/web/MockRequestDispatcher.java | 28 +- .../mock/web/MockServletContext.java | 257 +++++--- src/dist/changelog.txt | 1 + 16 files changed, 1678 insertions(+), 304 deletions(-) create mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java create mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java create mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java create mode 100644 spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java diff --git a/spring-orm/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-orm/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java index 94e627ede8..88660bb3ae 100644 --- a/spring-orm/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/spring-orm/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,22 +34,24 @@ import org.springframework.util.Assert; * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 */ public class MockRequestDispatcher implements RequestDispatcher { private final Log logger = LogFactory.getLog(getClass()); - private final String url; + private final String resource; /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. + * Create a new MockRequestDispatcher for the given resource. + * @param resource the server resource to dispatch to, located at a + * particular path or given by a particular name */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; + public MockRequestDispatcher(String resource) { + Assert.notNull(resource, "resource must not be null"); + this.resource = resource; } @@ -59,24 +61,24 @@ public class MockRequestDispatcher implements RequestDispatcher { if (response.isCommitted()) { throw new IllegalStateException("Cannot perform forward - response is already committed"); } - getMockHttpServletResponse(response).setForwardedUrl(this.url); + getMockHttpServletResponse(response).setForwardedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); } } public void include(ServletRequest request, ServletResponse response) { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); + getMockHttpServletResponse(response).addIncludedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: including [" + this.resource + "]"); } } /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link javax.servlet.http.HttpServletResponseWrapper} decorators if necessary. + * Obtain the underlying {@link MockHttpServletResponse}, unwrapping + * {@link HttpServletResponseWrapper} decorators if necessary. */ protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { if (response instanceof MockHttpServletResponse) { diff --git a/spring-orm/src/test/java/org/springframework/mock/web/MockServletContext.java b/spring-orm/src/test/java/org/springframework/mock/web/MockServletContext.java index e829e5708f..e3fa23eff3 100644 --- a/spring-orm/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-orm/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,28 +58,33 @@ import org.springframework.web.util.WebUtils; * *

Used for testing the Spring web framework; only rarely necessary for testing * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. + * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or + * {@code FileSystemXmlApplicationContext} can be used to load the context files + * for testing, even for {@code DispatcherServlet} context definitions. * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. + *

For setting up a full {@code WebApplicationContext} in a test environment, + * you can use {@code AnnotationConfigWebApplicationContext}, + * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, + * passing in an appropriate {@code MockServletContext} instance. You might want + * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} + * in that case to ensure that resource paths are interpreted as relative filesystem + * locations. * *

A common setup is to point your JVM working directory to the root of your * web application directory, in combination with filesystem-based resource loading. * This allows to load the context files as used in the web application, with * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). + * {@code FileSystemXmlApplicationContext} (which will load straight from the + * filesystem) and {@code XmlWebApplicationContext} with an underlying + * {@code MockServletContext} (as long as the {@code MockServletContext} has been + * configured with a {@code FileSystemResourceLoader}). * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext @@ -87,11 +92,23 @@ import org.springframework.web.util.WebUtils; */ public class MockServletContext implements ServletContext { - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; private final Log logger = LogFactory.getLog(getClass()); + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private final Set declaredRoles = new HashSet(); + + private final Map namedRequestDispatchers = new HashMap(); + private final ResourceLoader resourceLoader; private final String resourceBasePath; @@ -106,15 +123,9 @@ public class MockServletContext implements ServletContext { private int effectiveMinorVersion = 5; - private final Map contexts = new HashMap(); - - private final Map initParameters = new LinkedHashMap(); - - private final Map attributes = new LinkedHashMap(); - private String servletContextName = "MockServletContext"; - private final Set declaredRoles = new HashSet(); + private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME; /** @@ -128,7 +139,7 @@ public class MockServletContext implements ServletContext { /** * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @see org.springframework.core.io.DefaultResourceLoader */ public MockServletContext(String resourceBasePath) { @@ -145,9 +156,13 @@ public class MockServletContext implements ServletContext { } /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * Create a new MockServletContext using the supplied resource base path and + * resource loader. + *

Registers a {@link MockRequestDispatcher} for the Servlet named + * {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @param resourceLoader the ResourceLoader to use (or null for the default) + * @see #registerNamedDispatcher */ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); @@ -158,8 +173,9 @@ public class MockServletContext implements ServletContext { if (tempDir != null) { this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); } - } + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); + } /** * Build a full resource location for the given path, @@ -174,7 +190,6 @@ public class MockServletContext implements ServletContext { return this.resourceBasePath + path; } - public void setContextPath(String contextPath) { this.contextPath = (contextPath != null ? contextPath : ""); } @@ -295,7 +310,60 @@ public class MockServletContext implements ServletContext { } public RequestDispatcher getNamedDispatcher(String path) { - return null; + return this.namedRequestDispatchers.get(path); + } + + /** + * Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher}) + * that acts as a wrapper for the named Servlet. + * + * @param name the name of the wrapped Servlet + * @param requestDispatcher the dispatcher that wraps the named Servlet + * @see #getNamedDispatcher + * @see #unregisterNamedDispatcher + */ + public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + Assert.notNull(requestDispatcher, "RequestDispatcher must not be null"); + this.namedRequestDispatchers.put(name, requestDispatcher); + } + + /** + * Unregister the {@link RequestDispatcher} with the given name. + * + * @param name the name of the dispatcher to unregister + * @see #getNamedDispatcher + * @see #registerNamedDispatcher + */ + public void unregisterNamedDispatcher(String name) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + this.namedRequestDispatchers.remove(name); + } + + /** + * Get the name of the default {@code Servlet}. + *

Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @see #setDefaultServletName + */ + public String getDefaultServletName() { + return this.defaultServletName; + } + + /** + * Set the name of the default {@code Servlet}. + *

Also {@link #unregisterNamedDispatcher unregisters} the current default + * {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces} + * it with a {@link MockRequestDispatcher} for the provided + * {@code defaultServletName}. + * @param defaultServletName the name of the default {@code Servlet}; + * never {@code null} or empty + * @see #getDefaultServletName + */ + public void setDefaultServletName(String defaultServletName) { + Assert.hasText(defaultServletName, "defaultServletName must not be null or empty"); + unregisterNamedDispatcher(this.defaultServletName); + this.defaultServletName = defaultServletName; + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); } public Servlet getServlet(String name) { @@ -410,7 +478,7 @@ public class MockServletContext implements ServletContext { /** - * Inner factory class used to just introduce a Java Activation Framework + * Inner factory class used to introduce a Java Activation Framework * dependency when actually asked to resolve a MIME type. */ private static class MimeTypeResolver { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java index a87bea43c9..88660bb3ae 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,22 +34,24 @@ import org.springframework.util.Assert; * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 */ public class MockRequestDispatcher implements RequestDispatcher { private final Log logger = LogFactory.getLog(getClass()); - private final String url; + private final String resource; /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. + * Create a new MockRequestDispatcher for the given resource. + * @param resource the server resource to dispatch to, located at a + * particular path or given by a particular name */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; + public MockRequestDispatcher(String resource) { + Assert.notNull(resource, "resource must not be null"); + this.resource = resource; } @@ -59,24 +61,24 @@ public class MockRequestDispatcher implements RequestDispatcher { if (response.isCommitted()) { throw new IllegalStateException("Cannot perform forward - response is already committed"); } - getMockHttpServletResponse(response).setForwardedUrl(this.url); + getMockHttpServletResponse(response).setForwardedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); } } public void include(ServletRequest request, ServletResponse response) { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); + getMockHttpServletResponse(response).addIncludedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: including [" + this.resource + "]"); } } /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. + * Obtain the underlying {@link MockHttpServletResponse}, unwrapping + * {@link HttpServletResponseWrapper} decorators if necessary. */ protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { if (response instanceof MockHttpServletResponse) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java index e829e5708f..8a33ee4b5b 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.Vector; + import javax.activation.FileTypeMap; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; @@ -58,28 +58,33 @@ import org.springframework.web.util.WebUtils; * *

Used for testing the Spring web framework; only rarely necessary for testing * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. + * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or + * {@code FileSystemXmlApplicationContext} can be used to load the context files + * for testing, even for {@code DispatcherServlet} context definitions. * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. + *

For setting up a full {@code WebApplicationContext} in a test environment, + * you can use {@code AnnotationConfigWebApplicationContext}, + * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, + * passing in an appropriate {@code MockServletContext} instance. You might want + * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} + * in that case to ensure that resource paths are interpreted as relative filesystem + * locations. * *

A common setup is to point your JVM working directory to the root of your * web application directory, in combination with filesystem-based resource loading. * This allows to load the context files as used in the web application, with * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). + * {@code FileSystemXmlApplicationContext} (which will load straight from the + * filesystem) and {@code XmlWebApplicationContext} with an underlying + * {@code MockServletContext} (as long as the {@code MockServletContext} has been + * configured with a {@code FileSystemResourceLoader}). * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext @@ -87,11 +92,23 @@ import org.springframework.web.util.WebUtils; */ public class MockServletContext implements ServletContext { - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; private final Log logger = LogFactory.getLog(getClass()); + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private final Set declaredRoles = new HashSet(); + + private final Map namedRequestDispatchers = new HashMap(); + private final ResourceLoader resourceLoader; private final String resourceBasePath; @@ -106,15 +123,9 @@ public class MockServletContext implements ServletContext { private int effectiveMinorVersion = 5; - private final Map contexts = new HashMap(); - - private final Map initParameters = new LinkedHashMap(); - - private final Map attributes = new LinkedHashMap(); - private String servletContextName = "MockServletContext"; - private final Set declaredRoles = new HashSet(); + private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME; /** @@ -128,7 +139,7 @@ public class MockServletContext implements ServletContext { /** * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @see org.springframework.core.io.DefaultResourceLoader */ public MockServletContext(String resourceBasePath) { @@ -145,9 +156,13 @@ public class MockServletContext implements ServletContext { } /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * Create a new MockServletContext using the supplied resource base path and + * resource loader. + *

Registers a {@link MockRequestDispatcher} for the Servlet named + * {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @param resourceLoader the ResourceLoader to use (or null for the default) + * @see #registerNamedDispatcher */ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); @@ -158,8 +173,9 @@ public class MockServletContext implements ServletContext { if (tempDir != null) { this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); } - } + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); + } /** * Build a full resource location for the given path, @@ -174,7 +190,6 @@ public class MockServletContext implements ServletContext { return this.resourceBasePath + path; } - public void setContextPath(String contextPath) { this.contextPath = (contextPath != null ? contextPath : ""); } @@ -295,7 +310,60 @@ public class MockServletContext implements ServletContext { } public RequestDispatcher getNamedDispatcher(String path) { - return null; + return this.namedRequestDispatchers.get(path); + } + + /** + * Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher}) + * that acts as a wrapper for the named Servlet. + * + * @param name the name of the wrapped Servlet + * @param requestDispatcher the dispatcher that wraps the named Servlet + * @see #getNamedDispatcher + * @see #unregisterNamedDispatcher + */ + public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + Assert.notNull(requestDispatcher, "RequestDispatcher must not be null"); + this.namedRequestDispatchers.put(name, requestDispatcher); + } + + /** + * Unregister the {@link RequestDispatcher} with the given name. + * + * @param name the name of the dispatcher to unregister + * @see #getNamedDispatcher + * @see #registerNamedDispatcher + */ + public void unregisterNamedDispatcher(String name) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + this.namedRequestDispatchers.remove(name); + } + + /** + * Get the name of the default {@code Servlet}. + *

Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @see #setDefaultServletName + */ + public String getDefaultServletName() { + return this.defaultServletName; + } + + /** + * Set the name of the default {@code Servlet}. + *

Also {@link #unregisterNamedDispatcher unregisters} the current default + * {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces} + * it with a {@link MockRequestDispatcher} for the provided + * {@code defaultServletName}. + * @param defaultServletName the name of the default {@code Servlet}; + * never {@code null} or empty + * @see #getDefaultServletName + */ + public void setDefaultServletName(String defaultServletName) { + Assert.hasText(defaultServletName, "defaultServletName must not be null or empty"); + unregisterNamedDispatcher(this.defaultServletName); + this.defaultServletName = defaultServletName; + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); } public Servlet getServlet(String name) { @@ -366,7 +434,7 @@ public class MockServletContext implements ServletContext { } public Enumeration getAttributeNames() { - return new Vector(this.attributes.keySet()).elements(); + return Collections.enumeration(this.attributes.keySet()); } public void setAttribute(String name, Object value) { @@ -410,7 +478,7 @@ public class MockServletContext implements ServletContext { /** - * Inner factory class used to just introduce a Java Activation Framework + * Inner factory class used to introduce a Java Activation Framework * dependency when actually asked to resolve a MIME type. */ private static class MimeTypeResolver { diff --git a/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java b/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java index 537d44be8e..f647ec7e6f 100644 --- a/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java +++ b/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java @@ -16,14 +16,12 @@ package org.springframework.mock.web; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.util.Set; +import javax.servlet.RequestDispatcher; + import org.junit.Test; /** @@ -34,39 +32,37 @@ import org.junit.Test; */ public class MockServletContextTests { + private final MockServletContext sc = new MockServletContext("org/springframework/mock"); + + @Test - public void testListFiles() { - MockServletContext sc = new MockServletContext("org/springframework/mock"); - Set paths = sc.getResourcePaths("/web"); + public void listFiles() { + Set paths = sc.getResourcePaths("/web"); assertNotNull(paths); assertTrue(paths.contains("/web/MockServletContextTests.class")); } @Test - public void testListSubdirectories() { - MockServletContext sc = new MockServletContext("org/springframework/mock"); - Set paths = sc.getResourcePaths("/"); + public void listSubdirectories() { + Set paths = sc.getResourcePaths("/"); assertNotNull(paths); assertTrue(paths.contains("/web/")); } @Test - public void testListNonDirectory() { - MockServletContext sc = new MockServletContext("org/springframework/mock"); - Set paths = sc.getResourcePaths("/web/MockServletContextTests.class"); + public void listNonDirectory() { + Set paths = sc.getResourcePaths("/web/MockServletContextTests.class"); assertNull(paths); } @Test - public void testListInvalidPath() { - MockServletContext sc = new MockServletContext("org/springframework/mock"); - Set paths = sc.getResourcePaths("/web/invalid"); + public void listInvalidPath() { + Set paths = sc.getResourcePaths("/web/invalid"); assertNull(paths); } @Test - public void testGetContext() { - MockServletContext sc = new MockServletContext(); + public void registerContextAndGetContext() { MockServletContext sc2 = new MockServletContext(); sc.setContextPath("/"); sc.registerContext("/second", sc2); @@ -75,18 +71,62 @@ public class MockServletContextTests { } @Test - public void testGetMimeType() { - MockServletContext sc = new MockServletContext(); + public void getMimeType() { assertEquals("text/html", sc.getMimeType("test.html")); assertEquals("image/gif", sc.getMimeType("test.gif")); } @Test - public void testMinorVersion() { - MockServletContext sc = new MockServletContext(); + public void minorVersion() { assertEquals(5, sc.getMinorVersion()); sc.setMinorVersion(4); assertEquals(4, sc.getMinorVersion()); } + @Test + public void registerAndUnregisterNamedDispatcher() throws Exception { + final String name = "test-servlet"; + final String url = "/test"; + + assertNull(sc.getNamedDispatcher(name)); + + sc.registerNamedDispatcher(name, new MockRequestDispatcher(url)); + RequestDispatcher namedDispatcher = sc.getNamedDispatcher(name); + assertNotNull(namedDispatcher); + MockHttpServletResponse response = new MockHttpServletResponse(); + namedDispatcher.forward(new MockHttpServletRequest(sc), response); + assertEquals(url, response.getForwardedUrl()); + + sc.unregisterNamedDispatcher(name); + assertNull(sc.getNamedDispatcher(name)); + } + + @Test + public void getNamedDispatcherForDefaultServlet() throws Exception { + final String name = "default"; + RequestDispatcher namedDispatcher = sc.getNamedDispatcher(name); + assertNotNull(namedDispatcher); + + MockHttpServletResponse response = new MockHttpServletResponse(); + namedDispatcher.forward(new MockHttpServletRequest(sc), response); + assertEquals(name, response.getForwardedUrl()); + } + + @Test + public void setDefaultServletName() throws Exception { + final String originalDefault = "default"; + final String newDefault = "test"; + assertNotNull(sc.getNamedDispatcher(originalDefault)); + + sc.setDefaultServletName(newDefault); + assertEquals(newDefault, sc.getDefaultServletName()); + assertNull(sc.getNamedDispatcher(originalDefault)); + + RequestDispatcher namedDispatcher = sc.getNamedDispatcher(newDefault); + assertNotNull(namedDispatcher); + MockHttpServletResponse response = new MockHttpServletResponse(); + namedDispatcher.forward(new MockHttpServletRequest(sc), response); + assertEquals(newDefault, response.getForwardedUrl()); + } + } diff --git a/spring-test/src/test/resources/log4j.xml b/spring-test/src/test/resources/log4j.xml index aec45e4ea9..bcfcb8f81a 100644 --- a/spring-test/src/test/resources/log4j.xml +++ b/spring-test/src/test/resources/log4j.xml @@ -47,7 +47,7 @@ - + diff --git a/spring-web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java index a87bea43c9..88660bb3ae 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/spring-web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,22 +34,24 @@ import org.springframework.util.Assert; * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 */ public class MockRequestDispatcher implements RequestDispatcher { private final Log logger = LogFactory.getLog(getClass()); - private final String url; + private final String resource; /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. + * Create a new MockRequestDispatcher for the given resource. + * @param resource the server resource to dispatch to, located at a + * particular path or given by a particular name */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; + public MockRequestDispatcher(String resource) { + Assert.notNull(resource, "resource must not be null"); + this.resource = resource; } @@ -59,24 +61,24 @@ public class MockRequestDispatcher implements RequestDispatcher { if (response.isCommitted()) { throw new IllegalStateException("Cannot perform forward - response is already committed"); } - getMockHttpServletResponse(response).setForwardedUrl(this.url); + getMockHttpServletResponse(response).setForwardedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); } } public void include(ServletRequest request, ServletResponse response) { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); + getMockHttpServletResponse(response).addIncludedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: including [" + this.resource + "]"); } } /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. + * Obtain the underlying {@link MockHttpServletResponse}, unwrapping + * {@link HttpServletResponseWrapper} decorators if necessary. */ protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { if (response instanceof MockHttpServletResponse) { diff --git a/spring-web/src/test/java/org/springframework/mock/web/MockServletContext.java b/spring-web/src/test/java/org/springframework/mock/web/MockServletContext.java index cd9d391735..cc9d164e83 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-web/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,10 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; + import javax.activation.FileTypeMap; import javax.servlet.Filter; import javax.servlet.FilterRegistration; -import javax.servlet.FilterRegistration.Dynamic; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; @@ -50,40 +50,51 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.ServletContext} interface. * + *

Compatible with Servlet 2.5 and partially with Servlet 3.0 but throws + * {@link UnsupportedOperationException} for most methods introduced in Servlet + * 3.0. Can be configured to expose a specific version through + * {@link #setMajorVersion}/{@link #setMinorVersion}; default is 2.5. Note that + * Servlet 3.0 support is limited: servlet, filter and listener registration + * methods are not supported; neither is cookie or JSP configuration. We generally + * do not recommend to unit-test your ServletContainerInitializers and + * WebApplicationInitializers which is where those registration methods would be used. + * *

Used for testing the Spring web framework; only rarely necessary for testing * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. + * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or + * {@code FileSystemXmlApplicationContext} can be used to load the context files + * for testing, even for {@code DispatcherServlet} context definitions. * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. + *

For setting up a full {@code WebApplicationContext} in a test environment, + * you can use {@code AnnotationConfigWebApplicationContext}, + * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, + * passing in an appropriate {@code MockServletContext} instance. You might want + * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} + * in that case to ensure that resource paths are interpreted as relative filesystem + * locations. * *

A common setup is to point your JVM working directory to the root of your * web application directory, in combination with filesystem-based resource loading. * This allows to load the context files as used in the web application, with * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). - * - *

Supports Servlet 3.0 API level, but throws {@link UnsupportedOperationException} - * for most methods introduced in Servlet 3.0. + * {@code FileSystemXmlApplicationContext} (which will load straight from the + * filesystem) and {@code XmlWebApplicationContext} with an underlying + * {@code MockServletContext} (as long as the {@code MockServletContext} has been + * configured with a {@code FileSystemResourceLoader}). * * @author Rod Johnson * @author Juergen Hoeller - * @author Chris Beams + * @author Sam Brannen * @since 1.0.2 * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext @@ -91,11 +102,23 @@ import org.springframework.web.util.WebUtils; */ public class MockServletContext implements ServletContext { - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; private final Log logger = LogFactory.getLog(getClass()); + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private final Set declaredRoles = new HashSet(); + + private final Map namedRequestDispatchers = new HashMap(); + private final ResourceLoader resourceLoader; private final String resourceBasePath; @@ -110,14 +133,10 @@ public class MockServletContext implements ServletContext { private int effectiveMinorVersion = 5; - private final Map contexts = new HashMap(); - - private final Map initParameters = new LinkedHashMap(); - - private final Map attributes = new LinkedHashMap(); - private String servletContextName = "MockServletContext"; + private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME; + /** * Create a new MockServletContext, using no base path and a @@ -130,7 +149,7 @@ public class MockServletContext implements ServletContext { /** * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @see org.springframework.core.io.DefaultResourceLoader */ public MockServletContext(String resourceBasePath) { @@ -147,9 +166,13 @@ public class MockServletContext implements ServletContext { } /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * Create a new MockServletContext using the supplied resource base path and + * resource loader. + *

Registers a {@link MockRequestDispatcher} for the Servlet named + * {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @param resourceLoader the ResourceLoader to use (or null for the default) + * @see #registerNamedDispatcher */ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); @@ -160,8 +183,9 @@ public class MockServletContext implements ServletContext { if (tempDir != null) { this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); } - } + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); + } /** * Build a full resource location for the given path, @@ -176,7 +200,6 @@ public class MockServletContext implements ServletContext { return this.resourceBasePath + path; } - public void setContextPath(String contextPath) { this.contextPath = (contextPath != null ? contextPath : ""); } @@ -297,7 +320,60 @@ public class MockServletContext implements ServletContext { } public RequestDispatcher getNamedDispatcher(String path) { - return null; + return this.namedRequestDispatchers.get(path); + } + + /** + * Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher}) + * that acts as a wrapper for the named Servlet. + * + * @param name the name of the wrapped Servlet + * @param requestDispatcher the dispatcher that wraps the named Servlet + * @see #getNamedDispatcher + * @see #unregisterNamedDispatcher + */ + public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + Assert.notNull(requestDispatcher, "RequestDispatcher must not be null"); + this.namedRequestDispatchers.put(name, requestDispatcher); + } + + /** + * Unregister the {@link RequestDispatcher} with the given name. + * + * @param name the name of the dispatcher to unregister + * @see #getNamedDispatcher + * @see #registerNamedDispatcher + */ + public void unregisterNamedDispatcher(String name) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + this.namedRequestDispatchers.remove(name); + } + + /** + * Get the name of the default {@code Servlet}. + *

Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @see #setDefaultServletName + */ + public String getDefaultServletName() { + return this.defaultServletName; + } + + /** + * Set the name of the default {@code Servlet}. + *

Also {@link #unregisterNamedDispatcher unregisters} the current default + * {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces} + * it with a {@link MockRequestDispatcher} for the provided + * {@code defaultServletName}. + * @param defaultServletName the name of the default {@code Servlet}; + * never {@code null} or empty + * @see #getDefaultServletName + */ + public void setDefaultServletName(String defaultServletName) { + Assert.hasText(defaultServletName, "defaultServletName must not be null or empty"); + unregisterNamedDispatcher(this.defaultServletName); + this.defaultServletName = defaultServletName; + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); } public Servlet getServlet(String name) { @@ -344,13 +420,22 @@ public class MockServletContext implements ServletContext { return this.initParameters.get(name); } - public void addInitParameter(String name, String value) { + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public boolean setInitParameter(String name, String value) { Assert.notNull(name, "Parameter name must not be null"); + if (this.initParameters.containsKey(name)) { + return false; + } this.initParameters.put(name, value); + return true; } - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); } public Object getAttribute(String name) { @@ -385,9 +470,25 @@ public class MockServletContext implements ServletContext { return this.servletContextName; } + public ClassLoader getClassLoader() { + return ClassUtils.getDefaultClassLoader(); + } + + public void declareRoles(String... roleNames) { + Assert.notNull(roleNames, "Role names array must not be null"); + for (String roleName : roleNames) { + Assert.hasLength(roleName, "Role name must not be empty"); + this.declaredRoles.add(roleName); + } + } + + public Set getDeclaredRoles() { + return Collections.unmodifiableSet(this.declaredRoles); + } + /** - * Inner factory class used to just introduce a Java Activation Framework + * Inner factory class used to introduce a Java Activation Framework * dependency when actually asked to resolve a MIME type. */ private static class MimeTypeResolver { @@ -402,67 +503,58 @@ public class MockServletContext implements ServletContext { // Methods introduced in Servlet 3.0 //--------------------------------------------------------------------- - public Dynamic addFilter(String arg0, String arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, String className) { throw new UnsupportedOperationException(); } - public Dynamic addFilter(String arg0, Filter arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { throw new UnsupportedOperationException(); } - public Dynamic addFilter(String arg0, Class arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { throw new UnsupportedOperationException(); } - public void addListener(Class arg0) { + public void addListener(Class listenerClass) { throw new UnsupportedOperationException(); } - public void addListener(String arg0) { + public void addListener(String className) { throw new UnsupportedOperationException(); } - public void addListener(T arg0) { + public void addListener(T t) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Servlet arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Class arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, + Class servletClass) { throw new UnsupportedOperationException(); } - public T createFilter(Class arg0) + public T createFilter(Class c) throws ServletException { throw new UnsupportedOperationException(); } - public T createListener(Class arg0) + public T createListener(Class c) throws ServletException { throw new UnsupportedOperationException(); } - public T createServlet(Class arg0) + public T createServlet(Class c) throws ServletException { throw new UnsupportedOperationException(); } - public void declareRoles(String... arg0) { - throw new UnsupportedOperationException(); - } - - public ClassLoader getClassLoader() { - throw new UnsupportedOperationException(); - } - public Set getDefaultSessionTrackingModes() { throw new UnsupportedOperationException(); } @@ -471,7 +563,7 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public FilterRegistration getFilterRegistration(String arg0) { + public FilterRegistration getFilterRegistration(String filterName) { throw new UnsupportedOperationException(); } @@ -483,7 +575,7 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public ServletRegistration getServletRegistration(String arg0) { + public ServletRegistration getServletRegistration(String servletName) { throw new UnsupportedOperationException(); } @@ -495,11 +587,7 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public boolean setInitParameter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public void setSessionTrackingModes(Set arg0) + public void setSessionTrackingModes(Set sessionTrackingModes) throws IllegalStateException, IllegalArgumentException { throw new UnsupportedOperationException(); } diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java new file mode 100644 index 0000000000..66fca5df2f --- /dev/null +++ b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.OutputStream; +import javax.servlet.ServletOutputStream; + +import org.springframework.util.Assert; + +/** + * Delegating implementation of {@link javax.servlet.ServletOutputStream}. + * + *

Used by {@link MockHttpServletResponse}; typically not directly + * used for testing application controllers. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see MockHttpServletResponse + */ +public class DelegatingServletOutputStream extends ServletOutputStream { + + private final OutputStream targetStream; + + + /** + * Create a DelegatingServletOutputStream for the given target stream. + * @param targetStream the target stream (never null) + */ + public DelegatingServletOutputStream(OutputStream targetStream) { + Assert.notNull(targetStream, "Target OutputStream must not be null"); + this.targetStream = targetStream; + } + + /** + * Return the underlying target stream (never null). + */ + public final OutputStream getTargetStream() { + return this.targetStream; + } + + + public void write(int b) throws IOException { + this.targetStream.write(b); + } + + public void flush() throws IOException { + super.flush(); + this.targetStream.flush(); + } + + public void close() throws IOException { + super.close(); + this.targetStream.close(); + } + +} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java new file mode 100644 index 0000000000..afe74ad8f0 --- /dev/null +++ b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Internal helper class that serves as value holder for request headers. + * + * @author Juergen Hoeller + * @author Rick Evans + * @since 2.0.1 + */ +class HeaderValueHolder { + + private final List values = new LinkedList(); + + + public void setValue(Object value) { + this.values.clear(); + this.values.add(value); + } + + public void addValue(Object value) { + this.values.add(value); + } + + public void addValues(Collection values) { + this.values.addAll(values); + } + + public void addValueArray(Object values) { + CollectionUtils.mergeArrayIntoCollection(values, this.values); + } + + public List getValues() { + return Collections.unmodifiableList(this.values); + } + + public List getStringValues() { + List stringList = new ArrayList(this.values.size()); + for (Object value : this.values) { + stringList.add(value.toString()); + } + return Collections.unmodifiableList(stringList); + } + + public Object getValue() { + return (!this.values.isEmpty() ? this.values.get(0) : null); + } + + public String getStringValue() { + return (!this.values.isEmpty() ? this.values.get(0).toString() : null); + } + + + /** + * Find a HeaderValueHolder by name, ignoring casing. + * @param headers the Map of header names to HeaderValueHolders + * @param name the name of the desired header + * @return the corresponding HeaderValueHolder, + * or null if none found + */ + public static HeaderValueHolder getByName(Map headers, String name) { + Assert.notNull(name, "Header name must not be null"); + for (String headerName : headers.keySet()) { + if (headerName.equalsIgnoreCase(name)) { + return headers.get(headerName); + } + } + return null; + } + +} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java new file mode 100644 index 0000000000..3e2701c576 --- /dev/null +++ b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -0,0 +1,603 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.web.util.WebUtils; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface. + * + *

Compatible with Servlet 2.5 as well as Servlet 3.0. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @since 1.0.2 + */ +public class MockHttpServletResponse implements HttpServletResponse { + + private static final String CHARSET_PREFIX = "charset="; + + private static final String CONTENT_TYPE_HEADER = "Content-Type"; + + private static final String CONTENT_LENGTH_HEADER = "Content-Length"; + + private static final String LOCATION_HEADER = "Location"; + + //--------------------------------------------------------------------- + // ServletResponse properties + //--------------------------------------------------------------------- + + private boolean outputStreamAccessAllowed = true; + + private boolean writerAccessAllowed = true; + + private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; + + private boolean charset = false; + + private final ByteArrayOutputStream content = new ByteArrayOutputStream(); + + private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content); + + private PrintWriter writer; + + private int contentLength = 0; + + private String contentType; + + private int bufferSize = 4096; + + private boolean committed; + + private Locale locale = Locale.getDefault(); + + + //--------------------------------------------------------------------- + // HttpServletResponse properties + //--------------------------------------------------------------------- + + private final List cookies = new ArrayList(); + + private final Map headers = new LinkedCaseInsensitiveMap(); + + private int status = HttpServletResponse.SC_OK; + + private String errorMessage; + + private String forwardedUrl; + + private final List includedUrls = new ArrayList(); + + + //--------------------------------------------------------------------- + // ServletResponse interface + //--------------------------------------------------------------------- + + /** + * Set whether {@link #getOutputStream()} access is allowed. + *

Default is true. + */ + public void setOutputStreamAccessAllowed(boolean outputStreamAccessAllowed) { + this.outputStreamAccessAllowed = outputStreamAccessAllowed; + } + + /** + * Return whether {@link #getOutputStream()} access is allowed. + */ + public boolean isOutputStreamAccessAllowed() { + return this.outputStreamAccessAllowed; + } + + /** + * Set whether {@link #getWriter()} access is allowed. + *

Default is true. + */ + public void setWriterAccessAllowed(boolean writerAccessAllowed) { + this.writerAccessAllowed = writerAccessAllowed; + } + + /** + * Return whether {@link #getOutputStream()} access is allowed. + */ + public boolean isWriterAccessAllowed() { + return this.writerAccessAllowed; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + this.charset = true; + updateContentTypeHeader(); + } + + private void updateContentTypeHeader() { + if (this.contentType != null) { + StringBuilder sb = new StringBuilder(this.contentType); + if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.charset) { + sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); + } + doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); + } + } + + public String getCharacterEncoding() { + return this.characterEncoding; + } + + public ServletOutputStream getOutputStream() { + if (!this.outputStreamAccessAllowed) { + throw new IllegalStateException("OutputStream access not allowed"); + } + return this.outputStream; + } + + public PrintWriter getWriter() throws UnsupportedEncodingException { + if (!this.writerAccessAllowed) { + throw new IllegalStateException("Writer access not allowed"); + } + if (this.writer == null) { + Writer targetWriter = (this.characterEncoding != null ? + new OutputStreamWriter(this.content, this.characterEncoding) : new OutputStreamWriter(this.content)); + this.writer = new ResponsePrintWriter(targetWriter); + } + return this.writer; + } + + public byte[] getContentAsByteArray() { + flushBuffer(); + return this.content.toByteArray(); + } + + public String getContentAsString() throws UnsupportedEncodingException { + flushBuffer(); + return (this.characterEncoding != null) ? + this.content.toString(this.characterEncoding) : this.content.toString(); + } + + public void setContentLength(int contentLength) { + this.contentLength = contentLength; + doAddHeaderValue(CONTENT_LENGTH_HEADER, contentLength, true); + } + + public int getContentLength() { + return this.contentLength; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + if (contentType != null) { + int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); + if (charsetIndex != -1) { + String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); + this.characterEncoding = encoding; + this.charset = true; + } + updateContentTypeHeader(); + } + } + + public String getContentType() { + return this.contentType; + } + + public void setBufferSize(int bufferSize) { + this.bufferSize = bufferSize; + } + + public int getBufferSize() { + return this.bufferSize; + } + + public void flushBuffer() { + setCommitted(true); + } + + public void resetBuffer() { + if (isCommitted()) { + throw new IllegalStateException("Cannot reset buffer - response is already committed"); + } + this.content.reset(); + } + + private void setCommittedIfBufferSizeExceeded() { + int bufSize = getBufferSize(); + if (bufSize > 0 && this.content.size() > bufSize) { + setCommitted(true); + } + } + + public void setCommitted(boolean committed) { + this.committed = committed; + } + + public boolean isCommitted() { + return this.committed; + } + + public void reset() { + resetBuffer(); + this.characterEncoding = null; + this.contentLength = 0; + this.contentType = null; + this.locale = null; + this.cookies.clear(); + this.headers.clear(); + this.status = HttpServletResponse.SC_OK; + this.errorMessage = null; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public Locale getLocale() { + return this.locale; + } + + + //--------------------------------------------------------------------- + // HttpServletResponse interface + //--------------------------------------------------------------------- + + public void addCookie(Cookie cookie) { + Assert.notNull(cookie, "Cookie must not be null"); + this.cookies.add(cookie); + } + + public Cookie[] getCookies() { + return this.cookies.toArray(new Cookie[this.cookies.size()]); + } + + public Cookie getCookie(String name) { + Assert.notNull(name, "Cookie name must not be null"); + for (Cookie cookie : this.cookies) { + if (name.equals(cookie.getName())) { + return cookie; + } + } + return null; + } + + public boolean containsHeader(String name) { + return (HeaderValueHolder.getByName(this.headers, name) != null); + } + + /** + * Return the names of all specified headers as a Set of Strings. + *

As of Servlet 3.0, this method is also defined HttpServletResponse. + * @return the Set of header name Strings, or an empty Set if none + */ + public Set getHeaderNames() { + return this.headers.keySet(); + } + + /** + * Return the primary value for the given header as a String, if any. + * Will return the first value in case of multiple values. + *

As of Servlet 3.0, this method is also defined in HttpServletResponse. + * As of Spring 3.1, it returns a stringified value for Servlet 3.0 compatibility. + * Consider using {@link #getHeaderValue(String)} for raw Object access. + * @param name the name of the header + * @return the associated header value, or null if none + */ + public String getHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return (header != null ? header.getStringValue() : null); + } + + /** + * Return all values for the given header as a List of Strings. + *

As of Servlet 3.0, this method is also defined in HttpServletResponse. + * As of Spring 3.1, it returns a List of stringified values for Servlet 3.0 compatibility. + * Consider using {@link #getHeaderValues(String)} for raw Object access. + * @param name the name of the header + * @return the associated header values, or an empty List if none + */ + public List getHeaders(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + if (header != null) { + return header.getStringValues(); + } + else { + return Collections.emptyList(); + } + } + + /** + * Return the primary value for the given header, if any. + *

Will return the first value in case of multiple values. + * @param name the name of the header + * @return the associated header value, or null if none + */ + public Object getHeaderValue(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return (header != null ? header.getValue() : null); + } + + /** + * Return all values for the given header as a List of value objects. + * @param name the name of the header + * @return the associated header values, or an empty List if none + */ + public List getHeaderValues(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + if (header != null) { + return header.getValues(); + } + else { + return Collections.emptyList(); + } + } + + /** + * The default implementation returns the given URL String as-is. + *

Can be overridden in subclasses, appending a session id or the like. + */ + public String encodeURL(String url) { + return url; + } + + /** + * The default implementation delegates to {@link #encodeURL}, + * returning the given URL String as-is. + *

Can be overridden in subclasses, appending a session id or the like + * in a redirect-specific fashion. For general URL encoding rules, + * override the common {@link #encodeURL} method instead, applying + * to redirect URLs as well as to general URLs. + */ + public String encodeRedirectURL(String url) { + return encodeURL(url); + } + + public String encodeUrl(String url) { + return encodeURL(url); + } + + public String encodeRedirectUrl(String url) { + return encodeRedirectURL(url); + } + + public void sendError(int status, String errorMessage) throws IOException { + if (isCommitted()) { + throw new IllegalStateException("Cannot set error status - response is already committed"); + } + this.status = status; + this.errorMessage = errorMessage; + setCommitted(true); + } + + public void sendError(int status) throws IOException { + if (isCommitted()) { + throw new IllegalStateException("Cannot set error status - response is already committed"); + } + this.status = status; + setCommitted(true); + } + + public void sendRedirect(String url) throws IOException { + if (isCommitted()) { + throw new IllegalStateException("Cannot send redirect - response is already committed"); + } + Assert.notNull(url, "Redirect URL must not be null"); + setHeader(LOCATION_HEADER, url); + setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + setCommitted(true); + } + + public String getRedirectedUrl() { + return getHeader(LOCATION_HEADER); + } + + public void setDateHeader(String name, long value) { + setHeaderValue(name, value); + } + + public void addDateHeader(String name, long value) { + addHeaderValue(name, value); + } + + public void setHeader(String name, String value) { + setHeaderValue(name, value); + } + + public void addHeader(String name, String value) { + addHeaderValue(name, value); + } + + public void setIntHeader(String name, int value) { + setHeaderValue(name, value); + } + + public void addIntHeader(String name, int value) { + addHeaderValue(name, value); + } + + private void setHeaderValue(String name, Object value) { + if (setSpecialHeader(name, value)) { + return; + } + doAddHeaderValue(name, value, true); + } + + private void addHeaderValue(String name, Object value) { + if (setSpecialHeader(name, value)) { + return; + } + doAddHeaderValue(name, value, false); + } + + private boolean setSpecialHeader(String name, Object value) { + if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) { + setContentType((String) value); + return true; + } + else if (CONTENT_LENGTH_HEADER.equalsIgnoreCase(name)) { + setContentLength(Integer.parseInt((String) value)); + return true; + } + else { + return false; + } + } + + private void doAddHeaderValue(String name, Object value, boolean replace) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Assert.notNull(value, "Header value must not be null"); + if (header == null) { + header = new HeaderValueHolder(); + this.headers.put(name, header); + } + if (replace) { + header.setValue(value); + } + else { + header.addValue(value); + } + } + + public void setStatus(int status) { + this.status = status; + } + + public void setStatus(int status, String errorMessage) { + this.status = status; + this.errorMessage = errorMessage; + } + + public int getStatus() { + return this.status; + } + + public String getErrorMessage() { + return this.errorMessage; + } + + + //--------------------------------------------------------------------- + // Methods for MockRequestDispatcher + //--------------------------------------------------------------------- + + public void setForwardedUrl(String forwardedUrl) { + this.forwardedUrl = forwardedUrl; + } + + public String getForwardedUrl() { + return this.forwardedUrl; + } + + public void setIncludedUrl(String includedUrl) { + this.includedUrls.clear(); + if (includedUrl != null) { + this.includedUrls.add(includedUrl); + } + } + + public String getIncludedUrl() { + int count = this.includedUrls.size(); + if (count > 1) { + throw new IllegalStateException( + "More than 1 URL included - check getIncludedUrls instead: " + this.includedUrls); + } + return (count == 1 ? this.includedUrls.get(0) : null); + } + + public void addIncludedUrl(String includedUrl) { + Assert.notNull(includedUrl, "Included URL must not be null"); + this.includedUrls.add(includedUrl); + } + + public List getIncludedUrls() { + return this.includedUrls; + } + + + /** + * Inner class that adapts the ServletOutputStream to mark the + * response as committed once the buffer size is exceeded. + */ + private class ResponseServletOutputStream extends DelegatingServletOutputStream { + + public ResponseServletOutputStream(OutputStream out) { + super(out); + } + + public void write(int b) throws IOException { + super.write(b); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + public void flush() throws IOException { + super.flush(); + setCommitted(true); + } + } + + + /** + * Inner class that adapts the PrintWriter to mark the + * response as committed once the buffer size is exceeded. + */ + private class ResponsePrintWriter extends PrintWriter { + + public ResponsePrintWriter(Writer out) { + super(out, true); + } + + public void write(char buf[], int off, int len) { + super.write(buf, off, len); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + public void write(String s, int off, int len) { + super.write(s, off, len); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + public void write(int c) { + super.write(c); + super.flush(); + setCommittedIfBufferSizeExceeded(); + } + + public void flush() { + super.flush(); + setCommitted(true); + } + } + +} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java new file mode 100644 index 0000000000..88660bb3ae --- /dev/null +++ b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. + * + *

Used for testing the web framework; typically not necessary for + * testing application controllers. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + * @since 1.0.2 + */ +public class MockRequestDispatcher implements RequestDispatcher { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String resource; + + + /** + * Create a new MockRequestDispatcher for the given resource. + * @param resource the server resource to dispatch to, located at a + * particular path or given by a particular name + */ + public MockRequestDispatcher(String resource) { + Assert.notNull(resource, "resource must not be null"); + this.resource = resource; + } + + + public void forward(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + if (response.isCommitted()) { + throw new IllegalStateException("Cannot perform forward - response is already committed"); + } + getMockHttpServletResponse(response).setForwardedUrl(this.resource); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); + } + } + + public void include(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + getMockHttpServletResponse(response).addIncludedUrl(this.resource); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: including [" + this.resource + "]"); + } + } + + /** + * Obtain the underlying {@link MockHttpServletResponse}, unwrapping + * {@link HttpServletResponseWrapper} decorators if necessary. + */ + protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { + if (response instanceof MockHttpServletResponse) { + return (MockHttpServletResponse) response; + } + if (response instanceof HttpServletResponseWrapper) { + return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse()); + } + throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse"); + } + +} diff --git a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockServletContext.java b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockServletContext.java index 5f2d2ca7d8..e3fa23eff3 100644 --- a/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-webmvc-portlet/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.Vector; import javax.activation.FileTypeMap; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; @@ -41,36 +42,49 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.ServletContext} interface. * + *

Compatible with Servlet 2.5 and partially with Servlet 3.0. Can be configured to + * expose a specific version through {@link #setMajorVersion}/{@link #setMinorVersion}; + * default is 2.5. Note that Servlet 3.0 support is limited: servlet, filter and listener + * registration methods are not supported; neither is cookie or JSP configuration. + * We generally do not recommend to unit-test your ServletContainerInitializers and + * WebApplicationInitializers which is where those registration methods would be used. + * *

Used for testing the Spring web framework; only rarely necessary for testing * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. + * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or + * {@code FileSystemXmlApplicationContext} can be used to load the context files + * for testing, even for {@code DispatcherServlet} context definitions. * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. + *

For setting up a full {@code WebApplicationContext} in a test environment, + * you can use {@code AnnotationConfigWebApplicationContext}, + * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, + * passing in an appropriate {@code MockServletContext} instance. You might want + * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} + * in that case to ensure that resource paths are interpreted as relative filesystem + * locations. * *

A common setup is to point your JVM working directory to the root of your * web application directory, in combination with filesystem-based resource loading. * This allows to load the context files as used in the web application, with * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). + * {@code FileSystemXmlApplicationContext} (which will load straight from the + * filesystem) and {@code XmlWebApplicationContext} with an underlying + * {@code MockServletContext} (as long as the {@code MockServletContext} has been + * configured with a {@code FileSystemResourceLoader}). * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext @@ -78,25 +92,41 @@ import org.springframework.web.util.WebUtils; */ public class MockServletContext implements ServletContext { - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; private final Log logger = LogFactory.getLog(getClass()); + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private final Set declaredRoles = new HashSet(); + + private final Map namedRequestDispatchers = new HashMap(); + private final ResourceLoader resourceLoader; private final String resourceBasePath; private String contextPath = ""; - private final Map contexts = new HashMap(); + private int majorVersion = 2; - private final Map initParameters = new LinkedHashMap(); + private int minorVersion = 5; - private final Map attributes = new LinkedHashMap(); + private int effectiveMajorVersion = 2; + + private int effectiveMinorVersion = 5; private String servletContextName = "MockServletContext"; + private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME; + /** * Create a new MockServletContext, using no base path and a @@ -109,7 +139,7 @@ public class MockServletContext implements ServletContext { /** * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @see org.springframework.core.io.DefaultResourceLoader */ public MockServletContext(String resourceBasePath) { @@ -126,9 +156,13 @@ public class MockServletContext implements ServletContext { } /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * Create a new MockServletContext using the supplied resource base path and + * resource loader. + *

Registers a {@link MockRequestDispatcher} for the Servlet named + * {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @param resourceLoader the ResourceLoader to use (or null for the default) + * @see #registerNamedDispatcher */ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); @@ -139,8 +173,9 @@ public class MockServletContext implements ServletContext { if (tempDir != null) { this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); } - } + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); + } /** * Build a full resource location for the given path, @@ -155,7 +190,6 @@ public class MockServletContext implements ServletContext { return this.resourceBasePath + path; } - public void setContextPath(String contextPath) { this.contextPath = (contextPath != null ? contextPath : ""); } @@ -176,12 +210,36 @@ public class MockServletContext implements ServletContext { return this.contexts.get(contextPath); } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public int getMajorVersion() { - return 2; + return this.majorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; } public int getMinorVersion() { - return 5; + return this.minorVersion; + } + + public void setEffectiveMajorVersion(int effectiveMajorVersion) { + this.effectiveMajorVersion = effectiveMajorVersion; + } + + public int getEffectiveMajorVersion() { + return this.effectiveMajorVersion; + } + + public void setEffectiveMinorVersion(int effectiveMinorVersion) { + this.effectiveMinorVersion = effectiveMinorVersion; + } + + public int getEffectiveMinorVersion() { + return this.effectiveMinorVersion; } public String getMimeType(String filePath) { @@ -245,11 +303,67 @@ public class MockServletContext implements ServletContext { } public RequestDispatcher getRequestDispatcher(String path) { - return null; + if (!path.startsWith("/")) { + throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'"); + } + return new MockRequestDispatcher(path); } public RequestDispatcher getNamedDispatcher(String path) { - return null; + return this.namedRequestDispatchers.get(path); + } + + /** + * Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher}) + * that acts as a wrapper for the named Servlet. + * + * @param name the name of the wrapped Servlet + * @param requestDispatcher the dispatcher that wraps the named Servlet + * @see #getNamedDispatcher + * @see #unregisterNamedDispatcher + */ + public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + Assert.notNull(requestDispatcher, "RequestDispatcher must not be null"); + this.namedRequestDispatchers.put(name, requestDispatcher); + } + + /** + * Unregister the {@link RequestDispatcher} with the given name. + * + * @param name the name of the dispatcher to unregister + * @see #getNamedDispatcher + * @see #registerNamedDispatcher + */ + public void unregisterNamedDispatcher(String name) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + this.namedRequestDispatchers.remove(name); + } + + /** + * Get the name of the default {@code Servlet}. + *

Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @see #setDefaultServletName + */ + public String getDefaultServletName() { + return this.defaultServletName; + } + + /** + * Set the name of the default {@code Servlet}. + *

Also {@link #unregisterNamedDispatcher unregisters} the current default + * {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces} + * it with a {@link MockRequestDispatcher} for the provided + * {@code defaultServletName}. + * @param defaultServletName the name of the default {@code Servlet}; + * never {@code null} or empty + * @see #getDefaultServletName + */ + public void setDefaultServletName(String defaultServletName) { + Assert.hasText(defaultServletName, "defaultServletName must not be null or empty"); + unregisterNamedDispatcher(this.defaultServletName); + this.defaultServletName = defaultServletName; + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); } public Servlet getServlet(String name) { @@ -296,13 +410,22 @@ public class MockServletContext implements ServletContext { return this.initParameters.get(name); } - public void addInitParameter(String name, String value) { + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public boolean setInitParameter(String name, String value) { Assert.notNull(name, "Parameter name must not be null"); + if (this.initParameters.containsKey(name)) { + return false; + } this.initParameters.put(name, value); + return true; } - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); } public Object getAttribute(String name) { @@ -311,7 +434,7 @@ public class MockServletContext implements ServletContext { } public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); + return new Vector(this.attributes.keySet()).elements(); } public void setAttribute(String name, Object value) { @@ -337,9 +460,25 @@ public class MockServletContext implements ServletContext { return this.servletContextName; } + public ClassLoader getClassLoader() { + return ClassUtils.getDefaultClassLoader(); + } + + public void declareRoles(String... roleNames) { + Assert.notNull(roleNames, "Role names array must not be null"); + for (String roleName : roleNames) { + Assert.hasLength(roleName, "Role name must not be empty"); + this.declaredRoles.add(roleName); + } + } + + public Set getDeclaredRoles() { + return Collections.unmodifiableSet(this.declaredRoles); + } + /** - * Inner factory class used to just introduce a Java Activation Framework + * Inner factory class used to introduce a Java Activation Framework * dependency when actually asked to resolve a MIME type. */ private static class MimeTypeResolver { diff --git a/spring-webmvc/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-webmvc/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java index a87bea43c9..88660bb3ae 100644 --- a/spring-webmvc/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/spring-webmvc/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,22 +34,24 @@ import org.springframework.util.Assert; * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 1.0.2 */ public class MockRequestDispatcher implements RequestDispatcher { private final Log logger = LogFactory.getLog(getClass()); - private final String url; + private final String resource; /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. + * Create a new MockRequestDispatcher for the given resource. + * @param resource the server resource to dispatch to, located at a + * particular path or given by a particular name */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; + public MockRequestDispatcher(String resource) { + Assert.notNull(resource, "resource must not be null"); + this.resource = resource; } @@ -59,24 +61,24 @@ public class MockRequestDispatcher implements RequestDispatcher { if (response.isCommitted()) { throw new IllegalStateException("Cannot perform forward - response is already committed"); } - getMockHttpServletResponse(response).setForwardedUrl(this.url); + getMockHttpServletResponse(response).setForwardedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); } } public void include(ServletRequest request, ServletResponse response) { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); + getMockHttpServletResponse(response).addIncludedUrl(this.resource); if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + logger.debug("MockRequestDispatcher: including [" + this.resource + "]"); } } /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. + * Obtain the underlying {@link MockHttpServletResponse}, unwrapping + * {@link HttpServletResponseWrapper} decorators if necessary. */ protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { if (response instanceof MockHttpServletResponse) { diff --git a/spring-webmvc/src/test/java/org/springframework/mock/web/MockServletContext.java b/spring-webmvc/src/test/java/org/springframework/mock/web/MockServletContext.java index 3e340f463a..6efd91095c 100644 --- a/spring-webmvc/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-webmvc/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,10 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; + import javax.activation.FileTypeMap; import javax.servlet.Filter; import javax.servlet.FilterRegistration; -import javax.servlet.FilterRegistration.Dynamic; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; @@ -50,40 +50,51 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.ServletContext} interface. * + *

Compatible with Servlet 2.5 and partially with Servlet 3.0 but throws + * {@link UnsupportedOperationException} for most methods introduced in Servlet + * 3.0. Can be configured to expose a specific version through + * {@link #setMajorVersion}/{@link #setMinorVersion}; default is 2.5. Note that + * Servlet 3.0 support is limited: servlet, filter and listener registration + * methods are not supported; neither is cookie or JSP configuration. We generally + * do not recommend to unit-test your ServletContainerInitializers and + * WebApplicationInitializers which is where those registration methods would be used. + * *

Used for testing the Spring web framework; only rarely necessary for testing * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. + * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or + * {@code FileSystemXmlApplicationContext} can be used to load the context files + * for testing, even for {@code DispatcherServlet} context definitions. * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. + *

For setting up a full {@code WebApplicationContext} in a test environment, + * you can use {@code AnnotationConfigWebApplicationContext}, + * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, + * passing in an appropriate {@code MockServletContext} instance. You might want + * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} + * in that case to ensure that resource paths are interpreted as relative filesystem + * locations. * *

A common setup is to point your JVM working directory to the root of your * web application directory, in combination with filesystem-based resource loading. * This allows to load the context files as used in the web application, with * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). - * - * Supports the Servlet 3.0 API level, but throws {@link UnsupportedOperationException} - * for all methods introduced in Servlet 3.0. + * {@code FileSystemXmlApplicationContext} (which will load straight from the + * filesystem) and {@code XmlWebApplicationContext} with an underlying + * {@code MockServletContext} (as long as the {@code MockServletContext} has been + * configured with a {@code FileSystemResourceLoader}). * * @author Rod Johnson * @author Juergen Hoeller - * @author Chris Beams + * @author Sam Brannen * @since 1.0.2 * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext @@ -91,27 +102,41 @@ import org.springframework.web.util.WebUtils; */ public class MockServletContext implements ServletContext { - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; private final Log logger = LogFactory.getLog(getClass()); + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private final Set declaredRoles = new HashSet(); + + private final Map namedRequestDispatchers = new HashMap(); + private final ResourceLoader resourceLoader; private final String resourceBasePath; private String contextPath = ""; - private int minorVersion = 5; + private int majorVersion = 2; - private final Map contexts = new HashMap(); + private int minorVersion = 5; - private final Map initParameters = new LinkedHashMap(); + private int effectiveMajorVersion = 2; - private final Map attributes = new LinkedHashMap(); + private int effectiveMinorVersion = 5; private String servletContextName = "MockServletContext"; + private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME; + /** * Create a new MockServletContext, using no base path and a @@ -124,7 +149,7 @@ public class MockServletContext implements ServletContext { /** * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @see org.springframework.core.io.DefaultResourceLoader */ public MockServletContext(String resourceBasePath) { @@ -141,9 +166,13 @@ public class MockServletContext implements ServletContext { } /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) + * Create a new MockServletContext using the supplied resource base path and + * resource loader. + *

Registers a {@link MockRequestDispatcher} for the Servlet named + * {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @param resourceBasePath the root directory of the WAR (should not end with a slash) * @param resourceLoader the ResourceLoader to use (or null for the default) + * @see #registerNamedDispatcher */ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); @@ -154,8 +183,9 @@ public class MockServletContext implements ServletContext { if (tempDir != null) { this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); } - } + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); + } /** * Build a full resource location for the given path, @@ -170,7 +200,6 @@ public class MockServletContext implements ServletContext { return this.resourceBasePath + path; } - public void setContextPath(String contextPath) { this.contextPath = (contextPath != null ? contextPath : ""); } @@ -191,14 +220,15 @@ public class MockServletContext implements ServletContext { return this.contexts.get(contextPath); } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public int getMajorVersion() { - return 2; + return this.majorVersion; } public void setMinorVersion(int minorVersion) { - if (minorVersion < 3 || minorVersion > 5) { - throw new IllegalArgumentException("Only Servlet minor versions between 3 and 5 are supported"); - } this.minorVersion = minorVersion; } @@ -206,6 +236,22 @@ public class MockServletContext implements ServletContext { return this.minorVersion; } + public void setEffectiveMajorVersion(int effectiveMajorVersion) { + this.effectiveMajorVersion = effectiveMajorVersion; + } + + public int getEffectiveMajorVersion() { + return this.effectiveMajorVersion; + } + + public void setEffectiveMinorVersion(int effectiveMinorVersion) { + this.effectiveMinorVersion = effectiveMinorVersion; + } + + public int getEffectiveMinorVersion() { + return this.effectiveMinorVersion; + } + public String getMimeType(String filePath) { return MimeTypeResolver.getMimeType(filePath); } @@ -274,7 +320,60 @@ public class MockServletContext implements ServletContext { } public RequestDispatcher getNamedDispatcher(String path) { - return null; + return this.namedRequestDispatchers.get(path); + } + + /** + * Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher}) + * that acts as a wrapper for the named Servlet. + * + * @param name the name of the wrapped Servlet + * @param requestDispatcher the dispatcher that wraps the named Servlet + * @see #getNamedDispatcher + * @see #unregisterNamedDispatcher + */ + public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + Assert.notNull(requestDispatcher, "RequestDispatcher must not be null"); + this.namedRequestDispatchers.put(name, requestDispatcher); + } + + /** + * Unregister the {@link RequestDispatcher} with the given name. + * + * @param name the name of the dispatcher to unregister + * @see #getNamedDispatcher + * @see #registerNamedDispatcher + */ + public void unregisterNamedDispatcher(String name) { + Assert.notNull(name, "RequestDispatcher name must not be null"); + this.namedRequestDispatchers.remove(name); + } + + /** + * Get the name of the default {@code Servlet}. + *

Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}. + * @see #setDefaultServletName + */ + public String getDefaultServletName() { + return this.defaultServletName; + } + + /** + * Set the name of the default {@code Servlet}. + *

Also {@link #unregisterNamedDispatcher unregisters} the current default + * {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces} + * it with a {@link MockRequestDispatcher} for the provided + * {@code defaultServletName}. + * @param defaultServletName the name of the default {@code Servlet}; + * never {@code null} or empty + * @see #getDefaultServletName + */ + public void setDefaultServletName(String defaultServletName) { + Assert.hasText(defaultServletName, "defaultServletName must not be null or empty"); + unregisterNamedDispatcher(this.defaultServletName); + this.defaultServletName = defaultServletName; + registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName)); } public Servlet getServlet(String name) { @@ -321,13 +420,22 @@ public class MockServletContext implements ServletContext { return this.initParameters.get(name); } - public void addInitParameter(String name, String value) { + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public boolean setInitParameter(String name, String value) { Assert.notNull(name, "Parameter name must not be null"); + if (this.initParameters.containsKey(name)) { + return false; + } this.initParameters.put(name, value); + return true; } - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); } public Object getAttribute(String name) { @@ -362,9 +470,25 @@ public class MockServletContext implements ServletContext { return this.servletContextName; } + public ClassLoader getClassLoader() { + return ClassUtils.getDefaultClassLoader(); + } + + public void declareRoles(String... roleNames) { + Assert.notNull(roleNames, "Role names array must not be null"); + for (String roleName : roleNames) { + Assert.hasLength(roleName, "Role name must not be empty"); + this.declaredRoles.add(roleName); + } + } + + public Set getDeclaredRoles() { + return Collections.unmodifiableSet(this.declaredRoles); + } + /** - * Inner factory class used to just introduce a Java Activation Framework + * Inner factory class used to introduce a Java Activation Framework * dependency when actually asked to resolve a MIME type. */ private static class MimeTypeResolver { @@ -375,68 +499,55 @@ public class MockServletContext implements ServletContext { } - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- // Methods introduced in Servlet 3.0 - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- - public Dynamic addFilter(String arg0, String arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, String className) { throw new UnsupportedOperationException(); } - public Dynamic addFilter(String arg0, Filter arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { throw new UnsupportedOperationException(); } - public Dynamic addFilter(String arg0, Class arg1) { + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { throw new UnsupportedOperationException(); } - public void addListener(Class arg0) { + public void addListener(Class listenerClass) { throw new UnsupportedOperationException(); } - public void addListener(String arg0) { + public void addListener(String className) { throw new UnsupportedOperationException(); } - public void addListener(T arg0) { + public void addListener(T t) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Servlet arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException(); } - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Class arg1) { + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { throw new UnsupportedOperationException(); } - public T createFilter(Class arg0) - throws ServletException { + public T createFilter(Class c) throws ServletException { throw new UnsupportedOperationException(); } - public T createListener(Class arg0) - throws ServletException { + public T createListener(Class c) throws ServletException { throw new UnsupportedOperationException(); } - public T createServlet(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public void declareRoles(String... arg0) { - throw new UnsupportedOperationException(); - } - - public ClassLoader getClassLoader() { + public T createServlet(Class c) throws ServletException { throw new UnsupportedOperationException(); } @@ -444,19 +555,11 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public int getEffectiveMajorVersion() { - throw new UnsupportedOperationException(); - } - - public int getEffectiveMinorVersion() { - throw new UnsupportedOperationException(); - } - public Set getEffectiveSessionTrackingModes() { throw new UnsupportedOperationException(); } - public FilterRegistration getFilterRegistration(String arg0) { + public FilterRegistration getFilterRegistration(String filterName) { throw new UnsupportedOperationException(); } @@ -468,7 +571,7 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public ServletRegistration getServletRegistration(String arg0) { + public ServletRegistration getServletRegistration(String servletName) { throw new UnsupportedOperationException(); } @@ -480,12 +583,8 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } - public boolean setInitParameter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public void setSessionTrackingModes(Set arg0) - throws IllegalStateException, IllegalArgumentException { + public void setSessionTrackingModes(Set sessionTrackingModes) throws IllegalStateException, + IllegalArgumentException { throw new UnsupportedOperationException(); } diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt index d77b3edf3c..d5406a535f 100644 --- a/src/dist/changelog.txt +++ b/src/dist/changelog.txt @@ -27,6 +27,7 @@ Changes in version 3.2 M2 (2012-08-xx) * fix issue with forward before async request processing * add exclude patterns for mapped interceptors in MVC namespace and MVC Java config * support content negotiation options in MVC namespace and MVC Java config +* support named dispatchers in MockServletContext (SPR-9587) Changes in version 3.2 M1 (2012-05-28)