Merge pull request #160 from sbrannen/SPR-5243
Support loading WebApplicationContexts in the TCF
This commit is contained in:
		
						commit
						9937f840d5
					
				| 
						 | 
				
			
			@ -1,94 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.web.mock.servlet.samples.context;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.RequestDispatcher;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
 | 
			
		||||
import org.springframework.context.annotation.AnnotationConfigUtils;
 | 
			
		||||
import org.springframework.core.io.DefaultResourceLoader;
 | 
			
		||||
import org.springframework.core.io.FileSystemResourceLoader;
 | 
			
		||||
import org.springframework.core.io.ResourceLoader;
 | 
			
		||||
import org.springframework.mock.web.MockRequestDispatcher;
 | 
			
		||||
import org.springframework.mock.web.MockServletContext;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.support.AbstractContextLoader;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
import org.springframework.web.context.support.GenericWebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is here temporarily until the TestContext framework provides
 | 
			
		||||
 * support for WebApplicationContext yet:
 | 
			
		||||
 *
 | 
			
		||||
 * https://jira.springsource.org/browse/SPR-5243
 | 
			
		||||
 *
 | 
			
		||||
 * <p>After that this class will no longer be needed. It's provided here as an example
 | 
			
		||||
 * and to serve as a temporary solution.
 | 
			
		||||
 */
 | 
			
		||||
public class GenericWebContextLoader extends AbstractContextLoader {
 | 
			
		||||
	protected final MockServletContext servletContext;
 | 
			
		||||
 | 
			
		||||
	public GenericWebContextLoader(String warRootDir, boolean isClasspathRelative) {
 | 
			
		||||
		ResourceLoader resourceLoader = isClasspathRelative ? new DefaultResourceLoader() : new FileSystemResourceLoader();
 | 
			
		||||
		this.servletContext = initServletContext(warRootDir, resourceLoader);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private MockServletContext initServletContext(String warRootDir, ResourceLoader resourceLoader) {
 | 
			
		||||
		return new MockServletContext(warRootDir, resourceLoader) {
 | 
			
		||||
			// Required for DefaultServletHttpRequestHandler...
 | 
			
		||||
			public RequestDispatcher getNamedDispatcher(String path) {
 | 
			
		||||
				return (path.equals("default")) ? new MockRequestDispatcher(path) : super.getNamedDispatcher(path);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
 | 
			
		||||
		GenericWebApplicationContext context = new GenericWebApplicationContext();
 | 
			
		||||
		context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
 | 
			
		||||
		prepareContext(context);
 | 
			
		||||
		loadBeanDefinitions(context, mergedConfig);
 | 
			
		||||
		return context;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public ApplicationContext loadContext(String... locations) throws Exception {
 | 
			
		||||
		// should never be called
 | 
			
		||||
		throw new UnsupportedOperationException();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected void prepareContext(GenericWebApplicationContext context) {
 | 
			
		||||
		this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
 | 
			
		||||
		context.setServletContext(this.servletContext);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected void loadBeanDefinitions(GenericWebApplicationContext context, String[] locations) {
 | 
			
		||||
		new XmlBeanDefinitionReader(context).loadBeanDefinitions(locations);
 | 
			
		||||
		AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
 | 
			
		||||
		context.refresh();
 | 
			
		||||
		context.registerShutdownHook();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected void loadBeanDefinitions(GenericWebApplicationContext context, MergedContextConfiguration mergedConfig) {
 | 
			
		||||
		new AnnotatedBeanDefinitionReader(context).register(mergedConfig.getClasses());
 | 
			
		||||
		loadBeanDefinitions(context, mergedConfig.getLocations());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	protected String getResourceSuffix() {
 | 
			
		||||
		return "-context.xml";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,9 +16,8 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.web.mock.servlet.samples.context;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,21 +25,20 @@ import org.junit.runner.RunWith;
 | 
			
		|||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 | 
			
		||||
import org.springframework.test.context.web.WebAppConfiguration;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.MockMvc;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
 | 
			
		||||
import org.springframework.web.context.ContextLoader;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests with Java configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * The TestContext framework doesn't support WebApplicationContext yet:
 | 
			
		||||
 * https://jira.springsource.org/browse/SPR-5243
 | 
			
		||||
 *
 | 
			
		||||
 * A custom {@link ContextLoader} is used to load the WebApplicationContext.
 | 
			
		||||
 * @author Rossen Stoyanchev
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(SpringJUnit4ClassRunner.class)
 | 
			
		||||
@ContextConfiguration(loader=WebContextLoader.class, classes={WebConfig.class})
 | 
			
		||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
 | 
			
		||||
@ContextConfiguration(classes = WebConfig.class)
 | 
			
		||||
public class JavaTestContextTests {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +46,7 @@ public class JavaTestContextTests {
 | 
			
		|||
 | 
			
		||||
	private MockMvc mockMvc;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Before
 | 
			
		||||
	public void setup() {
 | 
			
		||||
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
 | 
			
		||||
| 
						 | 
				
			
			@ -55,8 +54,8 @@ public class JavaTestContextTests {
 | 
			
		|||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void tilesDefinitions() throws Exception {
 | 
			
		||||
		this.mockMvc.perform(get("/"))
 | 
			
		||||
				.andExpect(status().isOk())
 | 
			
		||||
		this.mockMvc.perform(get("/"))//
 | 
			
		||||
		.andExpect(status().isOk())//
 | 
			
		||||
		.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
 * 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.test.web.mock.servlet.samples.context;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +35,7 @@ import org.springframework.security.web.FilterChainProxy;
 | 
			
		|||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 | 
			
		||||
import org.springframework.test.context.web.WebAppConfiguration;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.MockMvc;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.MvcResult;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.ResultMatcher;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,32 +46,25 @@ import org.springframework.web.context.WebApplicationContext;
 | 
			
		|||
/**
 | 
			
		||||
 * Basic example that includes Spring Security configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * <p>Note that currently there are no {@link ResultMatcher}' built specifically
 | 
			
		||||
 * for asserting the Spring Security context. However, it's quite easy to put
 | 
			
		||||
 * them together as shown below and Spring Security extensions will become
 | 
			
		||||
 * available in the near future.
 | 
			
		||||
 * <p>Note that currently there are no {@linkplain ResultMatcher ResultMatchers}
 | 
			
		||||
 * built specifically for asserting the Spring Security context. However, it's
 | 
			
		||||
 * quite easy to put them together as shown below, and Spring Security extensions
 | 
			
		||||
 * will become available in the near future.
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This also demonstrates a custom {@link RequestPostProcessor} which authenticates
 | 
			
		||||
 * a user to a particular {@link HttpServletRequest}.
 | 
			
		||||
 *
 | 
			
		||||
 * <p>Also see the Javadoc of {@link GenericWebContextLoader}, a class that
 | 
			
		||||
 * provides temporary support for loading WebApplicationContext by extending
 | 
			
		||||
 * the TestContext framework.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Rob Winch
 | 
			
		||||
 * @author Rossen Stoyanchev
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @see SecurityRequestPostProcessors
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(SpringJUnit4ClassRunner.class)
 | 
			
		||||
@ContextConfiguration(
 | 
			
		||||
		loader=WebContextLoader.class,
 | 
			
		||||
		value={
 | 
			
		||||
			"classpath:org/springframework/test/web/mock/servlet/samples/context/security.xml",
 | 
			
		||||
			"classpath:org/springframework/test/web/mock/servlet/samples/servlet-context.xml"
 | 
			
		||||
		})
 | 
			
		||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
 | 
			
		||||
@ContextConfiguration({ "security.xml", "../servlet-context.xml" })
 | 
			
		||||
public class SpringSecurityTests {
 | 
			
		||||
 | 
			
		||||
	private static String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
 | 
			
		||||
	private static final String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private FilterChainProxy springSecurityFilterChain;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,37 +74,44 @@ public class SpringSecurityTests {
 | 
			
		|||
 | 
			
		||||
	private MockMvc mockMvc;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Before
 | 
			
		||||
	public void setup() {
 | 
			
		||||
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
 | 
			
		||||
				.addFilters(this.springSecurityFilterChain).build();
 | 
			
		||||
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)//
 | 
			
		||||
		.addFilters(this.springSecurityFilterChain)//
 | 
			
		||||
		.build();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void requiresAuthentication() throws Exception {
 | 
			
		||||
		mockMvc.perform(get("/user"))
 | 
			
		||||
			.andExpect(redirectedUrl("http://localhost/spring_security_login"));
 | 
			
		||||
		mockMvc.perform(get("/user")).//
 | 
			
		||||
		andExpect(redirectedUrl("http://localhost/spring_security_login"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void accessGranted() throws Exception {
 | 
			
		||||
		this.mockMvc.perform(get("/").with(userDeatilsService("user")))
 | 
			
		||||
			.andExpect(status().isOk())
 | 
			
		||||
			.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
 | 
			
		||||
		this.mockMvc.perform(get("/").//
 | 
			
		||||
		with(userDeatilsService("user"))).//
 | 
			
		||||
		andExpect(status().isOk()).//
 | 
			
		||||
		andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void accessDenied() throws Exception {
 | 
			
		||||
		this.mockMvc.perform(get("/").with(user("user").roles("DENIED")))
 | 
			
		||||
		this.mockMvc.perform(get("/")//
 | 
			
		||||
		.with(user("user").roles("DENIED")))//
 | 
			
		||||
		.andExpect(status().isForbidden());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void userAuthenticates() throws Exception {
 | 
			
		||||
		final String username = "user";
 | 
			
		||||
		mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "password"))
 | 
			
		||||
			.andExpect(redirectedUrl("/"))
 | 
			
		||||
			.andExpect(new ResultMatcher() {
 | 
			
		||||
		mockMvc.perform(post("/j_spring_security_check").//
 | 
			
		||||
		param("j_username", username).//
 | 
			
		||||
		param("j_password", "password")).//
 | 
			
		||||
		andExpect(redirectedUrl("/")).//
 | 
			
		||||
		andExpect(new ResultMatcher() {
 | 
			
		||||
 | 
			
		||||
			public void match(MvcResult mvcResult) throws Exception {
 | 
			
		||||
				HttpSession session = mvcResult.getRequest().getSession();
 | 
			
		||||
				SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
 | 
			
		||||
| 
						 | 
				
			
			@ -121,9 +123,12 @@ public class SpringSecurityTests {
 | 
			
		|||
	@Test
 | 
			
		||||
	public void userAuthenticateFails() throws Exception {
 | 
			
		||||
		final String username = "user";
 | 
			
		||||
		mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "invalid"))
 | 
			
		||||
			.andExpect(redirectedUrl("/spring_security_login?login_error"))
 | 
			
		||||
			.andExpect(new ResultMatcher() {
 | 
			
		||||
		mockMvc.perform(post("/j_spring_security_check").//
 | 
			
		||||
		param("j_username", username).//
 | 
			
		||||
		param("j_password", "invalid")).//
 | 
			
		||||
		andExpect(redirectedUrl("/spring_security_login?login_error")).//
 | 
			
		||||
		andExpect(new ResultMatcher() {
 | 
			
		||||
 | 
			
		||||
			public void match(MvcResult mvcResult) throws Exception {
 | 
			
		||||
				HttpSession session = mvcResult.getRequest().getSession();
 | 
			
		||||
				SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,9 +16,8 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.web.mock.servlet.samples.context;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
 | 
			
		||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,23 +25,20 @@ import org.junit.runner.RunWith;
 | 
			
		|||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 | 
			
		||||
import org.springframework.test.context.web.WebAppConfiguration;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.MockMvc;
 | 
			
		||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
 | 
			
		||||
import org.springframework.web.context.ContextLoader;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests with XML configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * The TestContext framework doesn't support WebApplicationContext yet:
 | 
			
		||||
 * https://jira.springsource.org/browse/SPR-5243
 | 
			
		||||
 *
 | 
			
		||||
 * A custom {@link ContextLoader} is used to load the WebApplicationContext.
 | 
			
		||||
 * @author Rossen Stoyanchev
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(SpringJUnit4ClassRunner.class)
 | 
			
		||||
@ContextConfiguration(
 | 
			
		||||
		loader=WebContextLoader.class,
 | 
			
		||||
		locations={"/org/springframework/test/web/mock/servlet/samples/servlet-context.xml"})
 | 
			
		||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
 | 
			
		||||
@ContextConfiguration("../servlet-context.xml")
 | 
			
		||||
public class XmlTestContextTests {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +46,7 @@ public class XmlTestContextTests {
 | 
			
		|||
 | 
			
		||||
	private MockMvc mockMvc;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Before
 | 
			
		||||
	public void setup() {
 | 
			
		||||
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
 | 
			
		||||
| 
						 | 
				
			
			@ -57,10 +54,9 @@ public class XmlTestContextTests {
 | 
			
		|||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void tilesDefinitions() throws Exception {
 | 
			
		||||
		this.mockMvc.perform(get("/"))
 | 
			
		||||
				.andExpect(status().isOk())
 | 
			
		||||
		this.mockMvc.perform(get("/"))//
 | 
			
		||||
		.andExpect(status().isOk())//
 | 
			
		||||
		.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@
 | 
			
		|||
	<configs>
 | 
			
		||||
		<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
 | 
			
		||||
		<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
 | 
			
		||||
		<config>src/test/resources/org/springframework/test/context/web/BasicXmlWacTests-config.xml</config>
 | 
			
		||||
	</configs>
 | 
			
		||||
	<configSets>
 | 
			
		||||
	</configSets>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,8 +16,8 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.context;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.beans.BeanUtils.instantiateClass;
 | 
			
		||||
import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass;
 | 
			
		||||
import static org.springframework.beans.BeanUtils.*;
 | 
			
		||||
import static org.springframework.core.annotation.AnnotationUtils.*;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +30,8 @@ import org.apache.commons.logging.Log;
 | 
			
		|||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.context.ApplicationContextInitializer;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.test.context.web.WebAppConfiguration;
 | 
			
		||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +56,7 @@ abstract class ContextLoaderUtils {
 | 
			
		|||
	private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
 | 
			
		||||
 | 
			
		||||
	private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader";
 | 
			
		||||
	private static final String DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.WebDelegatingSmartContextLoader";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private ContextLoaderUtils() {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +86,8 @@ abstract class ContextLoaderUtils {
 | 
			
		|||
		Assert.notNull(testClass, "Test class must not be null");
 | 
			
		||||
 | 
			
		||||
		if (!StringUtils.hasText(defaultContextLoaderClassName)) {
 | 
			
		||||
			defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME;
 | 
			
		||||
			defaultContextLoaderClassName = testClass.isAnnotationPresent(WebAppConfiguration.class) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
 | 
			
		||||
					: DEFAULT_CONTEXT_LOADER_CLASS_NAME;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
 | 
			
		||||
| 
						 | 
				
			
			@ -394,6 +398,14 @@ abstract class ContextLoaderUtils {
 | 
			
		|||
		Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = resolveInitializerClasses(configAttributesList);
 | 
			
		||||
		String[] activeProfiles = resolveActiveProfiles(testClass);
 | 
			
		||||
 | 
			
		||||
		if (testClass.isAnnotationPresent(WebAppConfiguration.class)) {
 | 
			
		||||
			WebAppConfiguration webAppConfig = testClass.getAnnotation(WebAppConfiguration.class);
 | 
			
		||||
			String resourceBasePath = webAppConfig.value();
 | 
			
		||||
			return new WebMergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
 | 
			
		||||
				resourceBasePath, contextLoader);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// else
 | 
			
		||||
		return new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
 | 
			
		||||
			contextLoader);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ public class MergedContextConfiguration implements Serializable {
 | 
			
		|||
	 * {@link ContextLoader} based solely on the fully qualified name of the
 | 
			
		||||
	 * loader or "null" if the supplied loaded is <code>null</code>.
 | 
			
		||||
	 */
 | 
			
		||||
	private static String nullSafeToString(ContextLoader contextLoader) {
 | 
			
		||||
	protected static String nullSafeToString(ContextLoader contextLoader) {
 | 
			
		||||
		return contextLoader == null ? "null" : contextLoader.getClass().getName();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,6 +76,7 @@ import org.springframework.util.ObjectUtils;
 | 
			
		|||
public class TestContextManager {
 | 
			
		||||
 | 
			
		||||
	private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
 | 
			
		||||
		"org.springframework.test.context.web.WebTestExecutionListener",
 | 
			
		||||
		"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
 | 
			
		||||
		"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
 | 
			
		||||
		"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +127,6 @@ public class TestContextManager {
 | 
			
		|||
		return this.testContext;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register the supplied {@link TestExecutionListener TestExecutionListeners}
 | 
			
		||||
	 * by appending them to the set of listeners used by this <code>TestContextManager</code>.
 | 
			
		||||
| 
						 | 
				
			
			@ -155,8 +155,8 @@ public class TestContextManager {
 | 
			
		|||
	 * registered for this <code>TestContextManager</code> in reverse order.
 | 
			
		||||
	 */
 | 
			
		||||
	private List<TestExecutionListener> getReversedTestExecutionListeners() {
 | 
			
		||||
		List<TestExecutionListener> listenersReversed =
 | 
			
		||||
				new ArrayList<TestExecutionListener>(getTestExecutionListeners());
 | 
			
		||||
		List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
 | 
			
		||||
			getTestExecutionListeners());
 | 
			
		||||
		Collections.reverse(listenersReversed);
 | 
			
		||||
		return listenersReversed;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -186,8 +186,7 @@ public class TestContextManager {
 | 
			
		|||
			}
 | 
			
		||||
			classesList.addAll(getDefaultTestExecutionListenerClasses());
 | 
			
		||||
			defaultListeners = true;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		} else {
 | 
			
		||||
			// Traverse the class hierarchy...
 | 
			
		||||
			while (declaringClass != null) {
 | 
			
		||||
				TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
 | 
			
		||||
| 
						 | 
				
			
			@ -200,22 +199,21 @@ public class TestContextManager {
 | 
			
		|||
				Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
 | 
			
		||||
				if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
 | 
			
		||||
					String msg = String.format(
 | 
			
		||||
						"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] " +
 | 
			
		||||
								"and 'listeners' [%s] attributes. Use one or the other, but not both.",
 | 
			
		||||
						"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] "
 | 
			
		||||
								+ "and 'listeners' [%s] attributes. Use one or the other, but not both.",
 | 
			
		||||
						declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
 | 
			
		||||
						ObjectUtils.nullSafeToString(listenerClasses));
 | 
			
		||||
					logger.error(msg);
 | 
			
		||||
					throw new IllegalStateException(msg);
 | 
			
		||||
				}
 | 
			
		||||
				else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
 | 
			
		||||
				} else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
 | 
			
		||||
					listenerClasses = valueListenerClasses;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (listenerClasses != null) {
 | 
			
		||||
					classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
 | 
			
		||||
				}
 | 
			
		||||
				declaringClass = (testExecutionListeners.inheritListeners() ?
 | 
			
		||||
						AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null);
 | 
			
		||||
				declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
 | 
			
		||||
					annotationType, declaringClass.getSuperclass()) : null);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -223,16 +221,14 @@ public class TestContextManager {
 | 
			
		|||
		for (Class<? extends TestExecutionListener> listenerClass : classesList) {
 | 
			
		||||
			try {
 | 
			
		||||
				listeners.add(BeanUtils.instantiateClass(listenerClass));
 | 
			
		||||
			}
 | 
			
		||||
			catch (NoClassDefFoundError err) {
 | 
			
		||||
			} catch (NoClassDefFoundError err) {
 | 
			
		||||
				if (defaultListeners) {
 | 
			
		||||
					if (logger.isDebugEnabled()) {
 | 
			
		||||
						logger.debug("Could not instantiate default TestExecutionListener class ["
 | 
			
		||||
								+ listenerClass.getName()
 | 
			
		||||
								+ "]. Specify custom listener classes or make the default listener classes available.");
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
				} else {
 | 
			
		||||
					throw err;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -245,24 +241,21 @@ public class TestContextManager {
 | 
			
		|||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
 | 
			
		||||
		Set<Class<? extends TestExecutionListener>> defaultListenerClasses =
 | 
			
		||||
				new LinkedHashSet<Class<? extends TestExecutionListener>>();
 | 
			
		||||
		Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<Class<? extends TestExecutionListener>>();
 | 
			
		||||
		for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
 | 
			
		||||
			try {
 | 
			
		||||
				defaultListenerClasses.add(
 | 
			
		||||
						(Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className));
 | 
			
		||||
			}
 | 
			
		||||
			catch (Throwable ex) {
 | 
			
		||||
				defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(
 | 
			
		||||
					className));
 | 
			
		||||
			} catch (Throwable t) {
 | 
			
		||||
				if (logger.isDebugEnabled()) {
 | 
			
		||||
					logger.debug("Could not load default TestExecutionListener class [" + className
 | 
			
		||||
							+ "]. Specify custom listener classes or make the default listener classes available.");
 | 
			
		||||
							+ "]. Specify custom listener classes or make the default listener classes available.", t);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return defaultListenerClasses;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Hook for pre-processing a test class <em>before</em> execution of any
 | 
			
		||||
	 * tests within the class. Should be called prior to any framework-specific
 | 
			
		||||
| 
						 | 
				
			
			@ -286,8 +279,7 @@ public class TestContextManager {
 | 
			
		|||
		for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
 | 
			
		||||
			try {
 | 
			
		||||
				testExecutionListener.beforeTestClass(getTestContext());
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
 | 
			
		||||
						+ "] to process 'before class' callback for test class [" + testClass + "]", ex);
 | 
			
		||||
				throw ex;
 | 
			
		||||
| 
						 | 
				
			
			@ -319,8 +311,7 @@ public class TestContextManager {
 | 
			
		|||
		for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
 | 
			
		||||
			try {
 | 
			
		||||
				testExecutionListener.prepareTestInstance(getTestContext());
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				logger.error("Caught exception while allowing TestExecutionListener [" + testExecutionListener
 | 
			
		||||
						+ "] to prepare test instance [" + testInstance + "]", ex);
 | 
			
		||||
				throw ex;
 | 
			
		||||
| 
						 | 
				
			
			@ -356,8 +347,7 @@ public class TestContextManager {
 | 
			
		|||
		for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
 | 
			
		||||
			try {
 | 
			
		||||
				testExecutionListener.beforeTestMethod(getTestContext());
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
 | 
			
		||||
						+ "] to process 'before' execution of test method [" + testMethod + "] for test instance ["
 | 
			
		||||
						+ testInstance + "]", ex);
 | 
			
		||||
| 
						 | 
				
			
			@ -404,8 +394,7 @@ public class TestContextManager {
 | 
			
		|||
		for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
 | 
			
		||||
			try {
 | 
			
		||||
				testExecutionListener.afterTestMethod(getTestContext());
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
 | 
			
		||||
						+ "] to process 'after' execution for test: method [" + testMethod + "], instance ["
 | 
			
		||||
						+ testInstance + "], exception [" + exception + "]", ex);
 | 
			
		||||
| 
						 | 
				
			
			@ -446,8 +435,7 @@ public class TestContextManager {
 | 
			
		|||
		for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
 | 
			
		||||
			try {
 | 
			
		||||
				testExecutionListener.afterTestClass(getTestContext());
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
			} catch (Exception ex) {
 | 
			
		||||
				logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
 | 
			
		||||
						+ "] to process 'after class' callback for test class [" + testClass + "]", ex);
 | 
			
		||||
				if (afterTestClassException == null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,13 +16,24 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContextInitializer;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.core.GenericTypeResolver;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
 | 
			
		||||
import org.springframework.core.io.ClassPathResource;
 | 
			
		||||
import org.springframework.core.io.support.ResourcePatternUtils;
 | 
			
		||||
import org.springframework.test.context.ContextConfigurationAttributes;
 | 
			
		||||
import org.springframework.test.context.ContextLoader;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.SmartContextLoader;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +92,64 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
 | 
			
		|||
		configAttributes.setLocations(processedLocations);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Prepare the {@link ConfigurableApplicationContext} created by this 
 | 
			
		||||
	 * {@code SmartContextLoader} <i>before</i> bean definitions are read.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The default implementation:
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>Sets the <em>active bean definition profiles</em> from the supplied
 | 
			
		||||
	 * <code>MergedContextConfiguration</code> in the
 | 
			
		||||
	 * {@link org.springframework.core.env.Environment Environment} of the context.</li>
 | 
			
		||||
	 * <li>Determines what (if any) context initializer classes have been supplied
 | 
			
		||||
	 * via the {@code MergedContextConfiguration} and
 | 
			
		||||
	 * {@linkplain ApplicationContextInitializer#initialize invokes each} with the
 | 
			
		||||
	 * given application context.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>Any {@code ApplicationContextInitializers} implementing
 | 
			
		||||
	 * {@link org.springframework.core.Ordered Ordered} or marked with {@link
 | 
			
		||||
	 * org.springframework.core.annotation.Order @Order} will be sorted appropriately.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param context the newly created application context
 | 
			
		||||
	 * @param mergedConfig the merged context configuration
 | 
			
		||||
	 * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
 | 
			
		||||
	 * @see #loadContext(MergedContextConfiguration)
 | 
			
		||||
	 * @see ConfigurableApplicationContext#setId
 | 
			
		||||
	 * @since 3.2
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
 | 
			
		||||
 | 
			
		||||
		context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
 | 
			
		||||
 | 
			
		||||
		Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
 | 
			
		||||
 | 
			
		||||
		if (initializerClasses.size() == 0) {
 | 
			
		||||
			// no ApplicationContextInitializers have been declared -> nothing to do
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
 | 
			
		||||
		final Class<?> contextClass = context.getClass();
 | 
			
		||||
 | 
			
		||||
		for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
 | 
			
		||||
			Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
 | 
			
		||||
				ApplicationContextInitializer.class);
 | 
			
		||||
			Assert.isAssignable(initializerContextClass, contextClass, String.format(
 | 
			
		||||
				"Could not add context initializer [%s] since its generic parameter [%s] "
 | 
			
		||||
						+ "is not assignable from the type of application context used by this "
 | 
			
		||||
						+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
 | 
			
		||||
				contextClass.getName()));
 | 
			
		||||
			initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
 | 
			
		||||
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
 | 
			
		||||
			initializer.initialize(context);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- ContextLoader -------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -185,12 +254,10 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
 | 
			
		|||
			String path = locations[i];
 | 
			
		||||
			if (path.startsWith(SLASH)) {
 | 
			
		||||
				modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
 | 
			
		||||
			}
 | 
			
		||||
			else if (!ResourcePatternUtils.isUrl(path)) {
 | 
			
		||||
			} else if (!ResourcePatternUtils.isUrl(path)) {
 | 
			
		||||
				modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
 | 
			
		||||
						+ StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
			} else {
 | 
			
		||||
				modifiedLocations[i] = StringUtils.cleanPath(path);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,287 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.ContextConfigurationAttributes;
 | 
			
		||||
import org.springframework.test.context.ContextLoader;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.SmartContextLoader;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@code AbstractDelegatingSmartContextLoader} serves as an abstract base class
 | 
			
		||||
 * for implementations of the {@link SmartContextLoader} SPI that delegate to a
 | 
			
		||||
 * set of <em>candidate</em> SmartContextLoaders (i.e., one that supports XML
 | 
			
		||||
 * configuration files and one that supports annotated classes) to determine which
 | 
			
		||||
 * context loader is appropriate for a given test class's configuration. Each
 | 
			
		||||
 * candidate is given a chance to {@link #processContextConfiguration process} the
 | 
			
		||||
 * {@link ContextConfigurationAttributes} for each class in the test class hierarchy
 | 
			
		||||
 * that is annotated with {@link ContextConfiguration @ContextConfiguration}, and
 | 
			
		||||
 * the candidate that supports the merged, processed configuration will be used to
 | 
			
		||||
 * actually {@link #loadContext load} the context.
 | 
			
		||||
 * 
 | 
			
		||||
 * <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
 | 
			
		||||
 * that default resource locations (i.e., XML configuration files) or default
 | 
			
		||||
 * {@link org.springframework.context.annotation.Configuration configuration classes}
 | 
			
		||||
 * should be detected. Furthermore, if a specific {@link ContextLoader} or
 | 
			
		||||
 * {@link SmartContextLoader} is not explicitly declared via
 | 
			
		||||
 * {@code @ContextConfiguration}, a concrete subclass of
 | 
			
		||||
 * {@code AbstractDelegatingSmartContextLoader} will be used as the default loader,
 | 
			
		||||
 * thus providing automatic support for either XML configuration files or annotated
 | 
			
		||||
 * classes, but not both simultaneously.
 | 
			
		||||
 * 
 | 
			
		||||
 * <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
 | 
			
		||||
 * files nor annotated classes and instead declare only {@linkplain
 | 
			
		||||
 * ContextConfiguration#initializers application context initializers}. In such
 | 
			
		||||
 * cases, an attempt will still be made to detect defaults, but their absence will
 | 
			
		||||
 * not result an an exception.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 * @see SmartContextLoader
 | 
			
		||||
 */
 | 
			
		||||
abstract class AbstractDelegatingSmartContextLoader implements SmartContextLoader {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(AbstractDelegatingSmartContextLoader.class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the delegate {@code SmartContextLoader} that supports XML configuration files.
 | 
			
		||||
	 */
 | 
			
		||||
	protected abstract SmartContextLoader getXmlLoader();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the delegate {@code SmartContextLoader} that supports annotated classes.
 | 
			
		||||
	 */
 | 
			
		||||
	protected abstract SmartContextLoader getAnnotationConfigLoader();
 | 
			
		||||
 | 
			
		||||
	// --- SmartContextLoader --------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	private static String name(SmartContextLoader loader) {
 | 
			
		||||
		return loader.getClass().getSimpleName();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
 | 
			
		||||
				configAttributes));
 | 
			
		||||
		}
 | 
			
		||||
		loader.processContextConfiguration(configAttributes);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
 | 
			
		||||
			throws Exception {
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
 | 
			
		||||
		}
 | 
			
		||||
		return loader.loadContext(mergedConfig);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
 | 
			
		||||
		if (loader == getAnnotationConfigLoader()) {
 | 
			
		||||
			return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
 | 
			
		||||
		} else {
 | 
			
		||||
			return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delegates to candidate {@code SmartContextLoaders} to process the supplied
 | 
			
		||||
	 * {@link ContextConfigurationAttributes}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <p>Delegation is based on explicit knowledge of the implementations of the
 | 
			
		||||
	 * default loaders for {@link #getXmlLoader() XML configuration files} and
 | 
			
		||||
	 * {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
 | 
			
		||||
	 * delegation algorithm is as follows:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>If the resource locations or annotated classes in the supplied
 | 
			
		||||
	 * {@code ContextConfigurationAttributes} are not empty, the appropriate 
 | 
			
		||||
	 * candidate loader will be allowed to process the configuration <em>as is</em>,
 | 
			
		||||
	 * without any checks for detection of defaults.</li>
 | 
			
		||||
	 * <li>Otherwise, the XML-based loader will be allowed to process
 | 
			
		||||
	 * the configuration in order to detect default resource locations. If
 | 
			
		||||
	 * the XML-based loader detects default resource locations,
 | 
			
		||||
	 * an {@code info} message will be logged.</li>
 | 
			
		||||
	 * <li>Subsequently, the annotation-based loader will be allowed to
 | 
			
		||||
	 * process the configuration in order to detect default configuration classes.
 | 
			
		||||
	 * If the annotation-based loader detects default configuration
 | 
			
		||||
	 * classes, an {@code info} message will be logged.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param configAttributes the context configuration attributes to process
 | 
			
		||||
	 * @throws IllegalArgumentException if the supplied configuration attributes are
 | 
			
		||||
	 * <code>null</code>, or if the supplied configuration attributes include both
 | 
			
		||||
	 * resource locations and annotated classes
 | 
			
		||||
	 * @throws IllegalStateException if the XML-based loader detects default
 | 
			
		||||
	 * configuration classes; if the annotation-based loader detects default
 | 
			
		||||
	 * resource locations; if neither candidate loader detects defaults for the supplied
 | 
			
		||||
	 * context configuration; or if both candidate loaders detect defaults for the
 | 
			
		||||
	 * supplied context configuration
 | 
			
		||||
	 */
 | 
			
		||||
	public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
 | 
			
		||||
 | 
			
		||||
		Assert.notNull(configAttributes, "configAttributes must not be null");
 | 
			
		||||
		Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
 | 
			
		||||
			"Cannot process locations AND classes for context "
 | 
			
		||||
					+ "configuration %s; configure one or the other, but not both.", configAttributes));
 | 
			
		||||
 | 
			
		||||
		// If the original locations or classes were not empty, there's no
 | 
			
		||||
		// need to bother with default detection checks; just let the
 | 
			
		||||
		// appropriate loader process the configuration.
 | 
			
		||||
		if (configAttributes.hasLocations()) {
 | 
			
		||||
			delegateProcessing(getXmlLoader(), configAttributes);
 | 
			
		||||
		} else if (configAttributes.hasClasses()) {
 | 
			
		||||
			delegateProcessing(getAnnotationConfigLoader(), configAttributes);
 | 
			
		||||
		} else {
 | 
			
		||||
			// Else attempt to detect defaults...
 | 
			
		||||
 | 
			
		||||
			// Let the XML loader process the configuration.
 | 
			
		||||
			delegateProcessing(getXmlLoader(), configAttributes);
 | 
			
		||||
			boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
 | 
			
		||||
 | 
			
		||||
			if (xmlLoaderDetectedDefaults) {
 | 
			
		||||
				if (logger.isInfoEnabled()) {
 | 
			
		||||
					logger.info(String.format("%s detected default locations for context configuration %s.",
 | 
			
		||||
						name(getXmlLoader()), configAttributes));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasClasses()) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"%s should NOT have detected default configuration classes for context configuration %s.",
 | 
			
		||||
					name(getXmlLoader()), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Now let the annotation config loader process the configuration.
 | 
			
		||||
			delegateProcessing(getAnnotationConfigLoader(), configAttributes);
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasClasses()) {
 | 
			
		||||
				if (logger.isInfoEnabled()) {
 | 
			
		||||
					logger.info(String.format(
 | 
			
		||||
						"%s detected default configuration classes for context configuration %s.",
 | 
			
		||||
						name(getAnnotationConfigLoader()), configAttributes));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"%s should NOT have detected default locations for context configuration %s.",
 | 
			
		||||
					name(getAnnotationConfigLoader()), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If neither loader detected defaults and no initializers were declared,
 | 
			
		||||
			// throw an exception.
 | 
			
		||||
			if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers "
 | 
			
		||||
							+ "were declared for context configuration %s", name(getXmlLoader()),
 | 
			
		||||
					name(getAnnotationConfigLoader()), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
 | 
			
		||||
				String message = String.format(
 | 
			
		||||
					"Configuration error: both default locations AND default configuration classes "
 | 
			
		||||
							+ "were detected for context configuration %s; configure one or the other, but not both.",
 | 
			
		||||
					configAttributes);
 | 
			
		||||
				logger.error(message);
 | 
			
		||||
				throw new IllegalStateException(message);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delegates to an appropriate candidate {@code SmartContextLoader} to load
 | 
			
		||||
	 * an {@link ApplicationContext}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <p>Delegation is based on explicit knowledge of the implementations of the
 | 
			
		||||
	 * default loaders for {@link #getXmlLoader() XML configuration files} and
 | 
			
		||||
	 * {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
 | 
			
		||||
	 * delegation algorithm is as follows:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>If the resource locations in the supplied {@code MergedContextConfiguration}
 | 
			
		||||
	 * are not empty and the annotated classes are empty,
 | 
			
		||||
	 * the XML-based loader will load the {@code ApplicationContext}.</li>
 | 
			
		||||
	 * <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
 | 
			
		||||
	 * are not empty and the resource locations are empty,
 | 
			
		||||
	 * the annotation-based loader will load the {@code ApplicationContext}.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param mergedConfig the merged context configuration to use to load the application context
 | 
			
		||||
	 * @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
 | 
			
		||||
	 * @throws IllegalStateException if neither candidate loader is capable of loading an
 | 
			
		||||
	 * {@code ApplicationContext} from the supplied merged context configuration
 | 
			
		||||
	 */
 | 
			
		||||
	public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
 | 
			
		||||
		Assert.notNull(mergedConfig, "mergedConfig must not be null");
 | 
			
		||||
 | 
			
		||||
		List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader());
 | 
			
		||||
 | 
			
		||||
		for (SmartContextLoader loader : candidates) {
 | 
			
		||||
			// Determine if each loader can load a context from the mergedConfig. If it
 | 
			
		||||
			// can, let it; otherwise, keep iterating.
 | 
			
		||||
			if (supports(loader, mergedConfig)) {
 | 
			
		||||
				return delegateLoading(loader, mergedConfig);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If neither of the candidates supports the mergedConfig based on resources but
 | 
			
		||||
		// ACIs were declared, then delegate to the annotation config loader.
 | 
			
		||||
		if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
 | 
			
		||||
			return delegateLoading(getAnnotationConfigLoader(), mergedConfig);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		throw new IllegalStateException(String.format(
 | 
			
		||||
			"Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()),
 | 
			
		||||
			name(getAnnotationConfigLoader()), mergedConfig));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- ContextLoader -------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code AbstractDelegatingSmartContextLoader} does not support the
 | 
			
		||||
	 * {@link ContextLoader#processLocations(Class, String...)} method. Call
 | 
			
		||||
	 * {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	public final String[] processLocations(Class<?> clazz, String... locations) {
 | 
			
		||||
		throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
 | 
			
		||||
				+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code AbstractDelegatingSmartContextLoader} does not support the
 | 
			
		||||
	 * {@link ContextLoader#loadContext(String...) } method. Call
 | 
			
		||||
	 * {@link #loadContext(MergedContextConfiguration)} instead.
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	public final ApplicationContext loadContext(String... locations) throws Exception {
 | 
			
		||||
		throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
 | 
			
		||||
				+ "Call loadContext(MergedContextConfiguration) instead.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,25 +16,14 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
 | 
			
		||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 | 
			
		||||
import org.springframework.context.ApplicationContextInitializer;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.AnnotationConfigUtils;
 | 
			
		||||
import org.springframework.context.support.GenericApplicationContext;
 | 
			
		||||
import org.springframework.core.GenericTypeResolver;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +66,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
 | 
			
		|||
	 *
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>Creates a {@link GenericApplicationContext} instance.</li>
 | 
			
		||||
	 * <li>Calls {@link #prepareContext(GenericApplicationContext, MergedContextConfiguration)}
 | 
			
		||||
	 * <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
 | 
			
		||||
	 * compatibility with the {@link org.springframework.test.context.ContextLoader
 | 
			
		||||
	 * ContextLoader} SPI.</li>
 | 
			
		||||
	 * <li>Calls {@link #prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)}
 | 
			
		||||
	 * to allow for customizing the context before bean definitions are loaded.</li>
 | 
			
		||||
	 * <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the
 | 
			
		||||
	 * context's <code>DefaultListableBeanFactory</code>.</li>
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +97,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		GenericApplicationContext context = new GenericApplicationContext();
 | 
			
		||||
		prepareContext(context);
 | 
			
		||||
		prepareContext(context, mergedConfig);
 | 
			
		||||
		customizeBeanFactory(context.getDefaultListableBeanFactory());
 | 
			
		||||
		loadBeanDefinitions(context, mergedConfig);
 | 
			
		||||
| 
						 | 
				
			
			@ -183,72 +176,6 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
 | 
			
		|||
	protected void prepareContext(GenericApplicationContext context) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Prepare the {@link GenericApplicationContext} created by this 
 | 
			
		||||
	 * {@code SmartContextLoader} <i>before</i> bean definitions are read.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The default implementation:
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
 | 
			
		||||
	 * compatibility with the {@link org.springframework.test.context.ContextLoader
 | 
			
		||||
	 * ContextLoader} SPI.</li>
 | 
			
		||||
	 * <li>Sets the <em>active bean definition profiles</em> from the supplied
 | 
			
		||||
	 * <code>MergedContextConfiguration</code> in the
 | 
			
		||||
	 * {@link org.springframework.core.env.Environment Environment} of the context.</li>
 | 
			
		||||
	 * <li>Determines what (if any) context initializer classes have been supplied
 | 
			
		||||
	 * via the {@code MergedContextConfiguration} and
 | 
			
		||||
	 * {@linkplain ApplicationContextInitializer#initialize invokes each} with the
 | 
			
		||||
	 * given application context.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>Any {@code ApplicationContextInitializers} implementing
 | 
			
		||||
	 * {@link org.springframework.core.Ordered Ordered} or marked with {@link
 | 
			
		||||
	 * org.springframework.core.annotation.Order @Order} will be sorted appropriately.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param applicationContext the newly created application context
 | 
			
		||||
	 * @param mergedConfig the merged context configuration
 | 
			
		||||
	 * @see ApplicationContextInitializer#initialize(GenericApplicationContext)
 | 
			
		||||
	 * @see #loadContext(MergedContextConfiguration)
 | 
			
		||||
	 * @see GenericApplicationContext#setAllowBeanDefinitionOverriding
 | 
			
		||||
	 * @see GenericApplicationContext#setResourceLoader
 | 
			
		||||
	 * @see GenericApplicationContext#setId
 | 
			
		||||
	 * @since 3.2
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	protected void prepareContext(GenericApplicationContext applicationContext,
 | 
			
		||||
			MergedContextConfiguration mergedConfig) {
 | 
			
		||||
 | 
			
		||||
		prepareContext(applicationContext);
 | 
			
		||||
 | 
			
		||||
		applicationContext.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
 | 
			
		||||
 | 
			
		||||
		Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
 | 
			
		||||
 | 
			
		||||
		if (initializerClasses.size() == 0) {
 | 
			
		||||
			// no ApplicationContextInitializers have been declared -> nothing to do
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
 | 
			
		||||
		final Class<?> contextClass = applicationContext.getClass();
 | 
			
		||||
 | 
			
		||||
		for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
 | 
			
		||||
			Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
 | 
			
		||||
				ApplicationContextInitializer.class);
 | 
			
		||||
			Assert.isAssignable(initializerContextClass, contextClass, String.format(
 | 
			
		||||
				"Could not add context initializer [%s] since its generic parameter [%s] "
 | 
			
		||||
						+ "is not assignable from the type of application context used by this "
 | 
			
		||||
						+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
 | 
			
		||||
				contextClass.getName()));
 | 
			
		||||
			initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
 | 
			
		||||
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
 | 
			
		||||
			initializer.initialize(applicationContext);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Customize the internal bean factory of the ApplicationContext created by
 | 
			
		||||
	 * this <code>ContextLoader</code>.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,126 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.ServletContext;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.AnnotationConfigUtils;
 | 
			
		||||
import org.springframework.core.io.DefaultResourceLoader;
 | 
			
		||||
import org.springframework.core.io.FileSystemResourceLoader;
 | 
			
		||||
import org.springframework.core.io.ResourceLoader;
 | 
			
		||||
import org.springframework.mock.web.MockServletContext;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
import org.springframework.web.context.support.GenericWebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document AbstractGenericWebContextLoader.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractGenericWebContextLoader extends AbstractContextLoader {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(AbstractGenericWebContextLoader.class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// --- SmartContextLoader -----------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden loadContext(MergedContextConfiguration).
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.SmartContextLoader#loadContext(org.springframework.test.context.MergedContextConfiguration)
 | 
			
		||||
	 */
 | 
			
		||||
	public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
 | 
			
		||||
 | 
			
		||||
		if (!(mergedConfig instanceof WebMergedContextConfiguration)) {
 | 
			
		||||
			throw new IllegalArgumentException(String.format(
 | 
			
		||||
				"Cannot load WebApplicationContext from non-web merged context configuration %s. "
 | 
			
		||||
						+ "Consider annotating your test class with @WebAppConfiguration.", mergedConfig));
 | 
			
		||||
		}
 | 
			
		||||
		WebMergedContextConfiguration webMergedConfig = (WebMergedContextConfiguration) mergedConfig;
 | 
			
		||||
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Loading WebApplicationContext for merged context configuration %s.",
 | 
			
		||||
				webMergedConfig));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		GenericWebApplicationContext context = new GenericWebApplicationContext();
 | 
			
		||||
		configureWebResources(context, webMergedConfig);
 | 
			
		||||
		prepareContext(context, webMergedConfig);
 | 
			
		||||
		customizeBeanFactory(context.getDefaultListableBeanFactory(), webMergedConfig);
 | 
			
		||||
		loadBeanDefinitions(context, webMergedConfig);
 | 
			
		||||
		AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
 | 
			
		||||
		customizeContext(context, webMergedConfig);
 | 
			
		||||
		context.refresh();
 | 
			
		||||
		context.registerShutdownHook();
 | 
			
		||||
		return context;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document configureWebResources().
 | 
			
		||||
	 */
 | 
			
		||||
	protected void configureWebResources(GenericWebApplicationContext context,
 | 
			
		||||
			WebMergedContextConfiguration webMergedConfig) {
 | 
			
		||||
 | 
			
		||||
		String resourceBasePath = webMergedConfig.getResourceBasePath();
 | 
			
		||||
		ResourceLoader resourceLoader = resourceBasePath.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX) ? new DefaultResourceLoader()
 | 
			
		||||
				: new FileSystemResourceLoader();
 | 
			
		||||
 | 
			
		||||
		ServletContext servletContext = new MockServletContext(resourceBasePath, resourceLoader);
 | 
			
		||||
		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
 | 
			
		||||
		context.setServletContext(servletContext);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document customizeBeanFactory().
 | 
			
		||||
	 */
 | 
			
		||||
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory,
 | 
			
		||||
			WebMergedContextConfiguration webMergedConfig) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document loadBeanDefinitions().
 | 
			
		||||
	 */
 | 
			
		||||
	protected abstract void loadBeanDefinitions(GenericWebApplicationContext context,
 | 
			
		||||
			WebMergedContextConfiguration webMergedConfig);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document customizeContext().
 | 
			
		||||
	 */
 | 
			
		||||
	protected void customizeContext(GenericWebApplicationContext context, WebMergedContextConfiguration webMergedConfig) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- ContextLoader -------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden loadContext(String...).
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.ContextLoader#loadContext(java.lang.String[])
 | 
			
		||||
	 */
 | 
			
		||||
	public final ApplicationContext loadContext(String... locations) throws Exception {
 | 
			
		||||
		throw new UnsupportedOperationException(
 | 
			
		||||
			"AbstractGenericWebContextLoader does not support the loadContext(String... locations) method");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,19 +16,13 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Modifier;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
 | 
			
		||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.context.support.GenericApplicationContext;
 | 
			
		||||
import org.springframework.test.context.ContextConfigurationAttributes;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -89,80 +83,19 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
 | 
			
		|||
 | 
			
		||||
	// --- AnnotationConfigContextLoader ---------------------------------------
 | 
			
		||||
 | 
			
		||||
	private boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
 | 
			
		||||
		Assert.notNull(clazz, "Class must not be null");
 | 
			
		||||
		int modifiers = clazz.getModifiers();
 | 
			
		||||
		return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Determine if the supplied {@link Class} meets the criteria for being
 | 
			
		||||
	 * considered a <em>default configuration class</em> candidate.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>Specifically, such candidates:
 | 
			
		||||
	 *
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>must not be <code>null</code></li>
 | 
			
		||||
	 * <li>must not be <code>private</code></li>
 | 
			
		||||
	 * <li>must not be <code>final</code></li>
 | 
			
		||||
	 * <li>must be <code>static</code></li>
 | 
			
		||||
	 * <li>must be annotated with {@code @Configuration}</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param clazz the class to check
 | 
			
		||||
	 * @return <code>true</code> if the supplied class meets the candidate criteria
 | 
			
		||||
	 */
 | 
			
		||||
	private boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
 | 
			
		||||
		return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Detect the default configuration classes for the supplied test class.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The returned class array will contain all static inner classes of
 | 
			
		||||
	 * the supplied class that meet the requirements for {@code @Configuration}
 | 
			
		||||
	 * class implementations as specified in the documentation for
 | 
			
		||||
	 * {@link Configuration @Configuration}.
 | 
			
		||||
	 * <p>The default implementation simply delegates to
 | 
			
		||||
	 * {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The implementation of this method adheres to the contract defined in the
 | 
			
		||||
	 * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
 | 
			
		||||
	 * SPI. Specifically, this method uses introspection to detect default
 | 
			
		||||
	 * configuration classes that comply with the constraints required of
 | 
			
		||||
	 * {@code @Configuration} class implementations. If a potential candidate
 | 
			
		||||
	 * configuration class does not meet these requirements, this method will log a
 | 
			
		||||
	 * warning, and the potential candidate class will be ignored.
 | 
			
		||||
	 * @param declaringClass the test class that declared {@code @ContextConfiguration}
 | 
			
		||||
	 * @return an array of default configuration classes, potentially empty but
 | 
			
		||||
	 * never <code>null</code>
 | 
			
		||||
	 * @see AnnotationConfigContextLoaderUtils
 | 
			
		||||
	 */
 | 
			
		||||
	protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
 | 
			
		||||
		Assert.notNull(declaringClass, "Declaring class must not be null");
 | 
			
		||||
 | 
			
		||||
		List<Class<?>> configClasses = new ArrayList<Class<?>>();
 | 
			
		||||
 | 
			
		||||
		for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
 | 
			
		||||
			if (isDefaultConfigurationClassCandidate(candidate)) {
 | 
			
		||||
				configClasses.add(candidate);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				if (logger.isDebugEnabled()) {
 | 
			
		||||
					logger.debug(String.format(
 | 
			
		||||
						"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
 | 
			
		||||
								+ "with @Configuration to be considered a default configuration class.",
 | 
			
		||||
						candidate.getName()));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (configClasses.isEmpty()) {
 | 
			
		||||
			if (logger.isInfoEnabled()) {
 | 
			
		||||
				logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
 | 
			
		||||
						+ "%s does not declare any static, non-private, non-final, inner classes "
 | 
			
		||||
						+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return configClasses.toArray(new Class<?>[configClasses.size()]);
 | 
			
		||||
		return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- AbstractContextLoader -----------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,118 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Modifier;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document AnnotationConfigContextLoaderUtils.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
abstract class AnnotationConfigContextLoaderUtils {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoaderUtils.class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private AnnotationConfigContextLoaderUtils() {
 | 
			
		||||
		/* no-op */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
 | 
			
		||||
		Assert.notNull(clazz, "Class must not be null");
 | 
			
		||||
		int modifiers = clazz.getModifiers();
 | 
			
		||||
		return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Determine if the supplied {@link Class} meets the criteria for being
 | 
			
		||||
	 * considered a <em>default configuration class</em> candidate.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>Specifically, such candidates:
 | 
			
		||||
	 *
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>must not be <code>null</code></li>
 | 
			
		||||
	 * <li>must not be <code>private</code></li>
 | 
			
		||||
	 * <li>must not be <code>final</code></li>
 | 
			
		||||
	 * <li>must be <code>static</code></li>
 | 
			
		||||
	 * <li>must be annotated with {@code @Configuration}</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param clazz the class to check
 | 
			
		||||
	 * @return <code>true</code> if the supplied class meets the candidate criteria
 | 
			
		||||
	 */
 | 
			
		||||
	private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
 | 
			
		||||
		return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Detect the default configuration classes for the supplied test class.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The returned class array will contain all static inner classes of
 | 
			
		||||
	 * the supplied class that meet the requirements for {@code @Configuration}
 | 
			
		||||
	 * class implementations as specified in the documentation for
 | 
			
		||||
	 * {@link Configuration @Configuration}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The implementation of this method adheres to the contract defined in the
 | 
			
		||||
	 * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
 | 
			
		||||
	 * SPI. Specifically, this method uses introspection to detect default
 | 
			
		||||
	 * configuration classes that comply with the constraints required of
 | 
			
		||||
	 * {@code @Configuration} class implementations. If a potential candidate
 | 
			
		||||
	 * configuration class does not meet these requirements, this method will log a
 | 
			
		||||
	 * warning, and the potential candidate class will be ignored.
 | 
			
		||||
	 * @param declaringClass the test class that declared {@code @ContextConfiguration}
 | 
			
		||||
	 * @return an array of default configuration classes, potentially empty but
 | 
			
		||||
	 * never <code>null</code>
 | 
			
		||||
	 */
 | 
			
		||||
	static Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
 | 
			
		||||
		Assert.notNull(declaringClass, "Declaring class must not be null");
 | 
			
		||||
 | 
			
		||||
		List<Class<?>> configClasses = new ArrayList<Class<?>>();
 | 
			
		||||
 | 
			
		||||
		for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
 | 
			
		||||
			if (isDefaultConfigurationClassCandidate(candidate)) {
 | 
			
		||||
				configClasses.add(candidate);
 | 
			
		||||
			} else {
 | 
			
		||||
				if (logger.isDebugEnabled()) {
 | 
			
		||||
					logger.debug(String.format(
 | 
			
		||||
						"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
 | 
			
		||||
								+ "with @Configuration to be considered a default configuration class.",
 | 
			
		||||
						candidate.getName()));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (configClasses.isEmpty()) {
 | 
			
		||||
			if (logger.isInfoEnabled()) {
 | 
			
		||||
				logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
 | 
			
		||||
						+ "%s does not declare any static, non-private, non-final, inner classes "
 | 
			
		||||
						+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return configClasses.toArray(new Class<?>[configClasses.size()]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
 | 
			
		||||
import org.springframework.test.context.ContextConfigurationAttributes;
 | 
			
		||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
import org.springframework.web.context.support.GenericWebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document AnnotationConfigWebContextLoader.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
public class AnnotationConfigWebContextLoader extends AbstractGenericWebContextLoader {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(AnnotationConfigWebContextLoader.class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// --- SmartContextLoader -----------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Process <em>annotated classes</em> in the supplied {@link ContextConfigurationAttributes}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>If the <em>annotated classes</em> are <code>null</code> or empty and
 | 
			
		||||
	 * {@link #isGenerateDefaultLocations()} returns <code>true</code>, this
 | 
			
		||||
	 * <code>SmartContextLoader</code> will attempt to {@link
 | 
			
		||||
	 * #detectDefaultConfigurationClasses detect default configuration classes}.
 | 
			
		||||
	 * If defaults are detected they will be
 | 
			
		||||
	 * {@link ContextConfigurationAttributes#setClasses(Class[]) set} in the
 | 
			
		||||
	 * supplied configuration attributes. Otherwise, properties in the supplied
 | 
			
		||||
	 * configuration attributes will not be modified.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param configAttributes the context configuration attributes to process
 | 
			
		||||
	 * @see org.springframework.test.context.SmartContextLoader#processContextConfiguration(ContextConfigurationAttributes)
 | 
			
		||||
	 * @see #isGenerateDefaultLocations()
 | 
			
		||||
	 * @see #detectDefaultConfigurationClasses(Class)
 | 
			
		||||
	 */
 | 
			
		||||
	public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
 | 
			
		||||
		if (ObjectUtils.isEmpty(configAttributes.getClasses()) && isGenerateDefaultLocations()) {
 | 
			
		||||
			Class<?>[] defaultConfigClasses = detectDefaultConfigurationClasses(configAttributes.getDeclaringClass());
 | 
			
		||||
			configAttributes.setClasses(defaultConfigClasses);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Detect the default configuration classes for the supplied test class.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The default implementation simply delegates to
 | 
			
		||||
	 * {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param declaringClass the test class that declared {@code @ContextConfiguration}
 | 
			
		||||
	 * @return an array of default configuration classes, potentially empty but
 | 
			
		||||
	 * never <code>null</code>
 | 
			
		||||
	 * @see AnnotationConfigContextLoaderUtils
 | 
			
		||||
	 */
 | 
			
		||||
	protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
 | 
			
		||||
		return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- AbstractContextLoader -----------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code AnnotationConfigWebContextLoader} should be used as a
 | 
			
		||||
	 * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
 | 
			
		||||
	 * not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
 | 
			
		||||
	 * Consequently, this method is not supported.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see AbstractContextLoader#modifyLocations
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected String[] modifyLocations(Class<?> clazz, String... locations) {
 | 
			
		||||
		throw new UnsupportedOperationException(
 | 
			
		||||
			"AnnotationConfigWebContextLoader does not support the modifyLocations(Class, String...) method");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code AnnotationConfigWebContextLoader} should be used as a
 | 
			
		||||
	 * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
 | 
			
		||||
	 * not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
 | 
			
		||||
	 * Consequently, this method is not supported.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see AbstractContextLoader#generateDefaultLocations
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected String[] generateDefaultLocations(Class<?> clazz) {
 | 
			
		||||
		throw new UnsupportedOperationException(
 | 
			
		||||
			"AnnotationConfigWebContextLoader does not support the generateDefaultLocations(Class) method");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code AnnotationConfigWebContextLoader} should be used as a
 | 
			
		||||
	 * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
 | 
			
		||||
	 * not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
 | 
			
		||||
	 * Consequently, this method is not supported.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see AbstractContextLoader#getResourceSuffix
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected String getResourceSuffix() {
 | 
			
		||||
		throw new UnsupportedOperationException(
 | 
			
		||||
			"AnnotationConfigWebContextLoader does not support the getResourceSuffix() method");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- AbstractGenericWebContextLoader -------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register classes in the supplied {@link GenericWebApplicationContext context}
 | 
			
		||||
	 * from the classes in the supplied {@link WebMergedContextConfiguration}.
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>Each class must represent an <em>annotated class</em>. An
 | 
			
		||||
	 * {@link AnnotatedBeanDefinitionReader} is used to register the appropriate
 | 
			
		||||
	 * bean definitions.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param context the context in which the annotated classes should be registered
 | 
			
		||||
	 * @param webMergedConfig the merged configuration from which the classes should be retrieved
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see AbstractGenericWebContextLoader#loadBeanDefinitions
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void loadBeanDefinitions(GenericWebApplicationContext context,
 | 
			
		||||
			WebMergedContextConfiguration webMergedConfig) {
 | 
			
		||||
		Class<?>[] annotatedClasses = webMergedConfig.getClasses();
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug("Registering annotated classes: " + ObjectUtils.nullSafeToString(annotatedClasses));
 | 
			
		||||
		}
 | 
			
		||||
		new AnnotatedBeanDefinitionReader(context).register(annotatedClasses);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,263 +16,32 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.test.context.support;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.ContextConfigurationAttributes;
 | 
			
		||||
import org.springframework.test.context.ContextLoader;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.SmartContextLoader;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@code DelegatingSmartContextLoader} is an implementation of the {@link SmartContextLoader}
 | 
			
		||||
 * SPI that delegates to a set of <em>candidate</em> SmartContextLoaders (i.e.,
 | 
			
		||||
 * {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}) to
 | 
			
		||||
 * determine which context loader is appropriate for a given test class's configuration.
 | 
			
		||||
 * Each candidate is given a chance to {@link #processContextConfiguration process} the
 | 
			
		||||
 * {@link ContextConfigurationAttributes} for each class in the test class hierarchy that
 | 
			
		||||
 * is annotated with {@link ContextConfiguration @ContextConfiguration}, and the candidate
 | 
			
		||||
 * that supports the merged, processed configuration will be used to actually
 | 
			
		||||
 * {@link #loadContext load} the context.
 | 
			
		||||
 * 
 | 
			
		||||
 * <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
 | 
			
		||||
 * that default resource locations (i.e., XML configuration files) or default
 | 
			
		||||
 * {@link org.springframework.context.annotation.Configuration configuration classes}
 | 
			
		||||
 * should be detected. Furthermore, if a specific {@link ContextLoader} or
 | 
			
		||||
 * {@link SmartContextLoader} is not explicitly declared via
 | 
			
		||||
 * {@code @ContextConfiguration}, {@code DelegatingSmartContextLoader} will be used as
 | 
			
		||||
 * the default loader, thus providing automatic support for either XML configuration
 | 
			
		||||
 * files or annotated classes, but not both simultaneously.
 | 
			
		||||
 * 
 | 
			
		||||
 * <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
 | 
			
		||||
 * files nor annotated classes and instead declare only {@linkplain
 | 
			
		||||
 * ContextConfiguration#initializers application context initializers}. In such
 | 
			
		||||
 * cases, an attempt will still be made to detect defaults, but their absence will
 | 
			
		||||
 * not result an an exception.
 | 
			
		||||
 * {@code DelegatingSmartContextLoader} is a concrete implementation of
 | 
			
		||||
 * {@link AbstractDelegatingSmartContextLoader} that delegates to a
 | 
			
		||||
 * {@link GenericXmlContextLoader} and an {@link AnnotationConfigContextLoader}.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.1
 | 
			
		||||
 * @see SmartContextLoader
 | 
			
		||||
 * @see AbstractDelegatingSmartContextLoader
 | 
			
		||||
 * @see GenericXmlContextLoader
 | 
			
		||||
 * @see AnnotationConfigContextLoader
 | 
			
		||||
 */
 | 
			
		||||
public class DelegatingSmartContextLoader implements SmartContextLoader {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(DelegatingSmartContextLoader.class);
 | 
			
		||||
public class DelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
 | 
			
		||||
 | 
			
		||||
	private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
 | 
			
		||||
	private final SmartContextLoader annotationConfigLoader = new AnnotationConfigContextLoader();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// --- SmartContextLoader --------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	private static String name(SmartContextLoader loader) {
 | 
			
		||||
		return loader.getClass().getSimpleName();
 | 
			
		||||
	protected SmartContextLoader getXmlLoader() {
 | 
			
		||||
		return this.xmlLoader;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
 | 
			
		||||
				configAttributes));
 | 
			
		||||
		}
 | 
			
		||||
		loader.processContextConfiguration(configAttributes);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
 | 
			
		||||
			throws Exception {
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
 | 
			
		||||
		}
 | 
			
		||||
		return loader.loadContext(mergedConfig);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
 | 
			
		||||
		if (loader instanceof AnnotationConfigContextLoader) {
 | 
			
		||||
			return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
 | 
			
		||||
		} else {
 | 
			
		||||
			return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delegates to candidate {@code SmartContextLoaders} to process the supplied
 | 
			
		||||
	 * {@link ContextConfigurationAttributes}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <p>Delegation is based on explicit knowledge of the implementations of
 | 
			
		||||
	 * {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
 | 
			
		||||
	 * Specifically, the delegation algorithm is as follows:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>If the resource locations or annotated classes in the supplied
 | 
			
		||||
	 * {@code ContextConfigurationAttributes} are not empty, the appropriate 
 | 
			
		||||
	 * candidate loader will be allowed to process the configuration <em>as is</em>,
 | 
			
		||||
	 * without any checks for detection of defaults.</li>
 | 
			
		||||
	 * <li>Otherwise, {@code GenericXmlContextLoader} will be allowed to process
 | 
			
		||||
	 * the configuration in order to detect default resource locations. If
 | 
			
		||||
	 * {@code GenericXmlContextLoader} detects default resource locations,
 | 
			
		||||
	 * an {@code info} message will be logged.</li>
 | 
			
		||||
	 * <li>Subsequently, {@code AnnotationConfigContextLoader} will be allowed to
 | 
			
		||||
	 * process the configuration in order to detect default configuration classes.
 | 
			
		||||
	 * If {@code AnnotationConfigContextLoader} detects default configuration
 | 
			
		||||
	 * classes, an {@code info} message will be logged.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param configAttributes the context configuration attributes to process
 | 
			
		||||
	 * @throws IllegalArgumentException if the supplied configuration attributes are
 | 
			
		||||
	 * <code>null</code>, or if the supplied configuration attributes include both
 | 
			
		||||
	 * resource locations and annotated classes
 | 
			
		||||
	 * @throws IllegalStateException if {@code GenericXmlContextLoader} detects default
 | 
			
		||||
	 * configuration classes; if {@code AnnotationConfigContextLoader} detects default
 | 
			
		||||
	 * resource locations; if neither candidate loader detects defaults for the supplied
 | 
			
		||||
	 * context configuration; or if both candidate loaders detect defaults for the
 | 
			
		||||
	 * supplied context configuration
 | 
			
		||||
	 */
 | 
			
		||||
	public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
 | 
			
		||||
 | 
			
		||||
		Assert.notNull(configAttributes, "configAttributes must not be null");
 | 
			
		||||
		Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
 | 
			
		||||
			"Cannot process locations AND classes for context "
 | 
			
		||||
					+ "configuration %s; configure one or the other, but not both.", configAttributes));
 | 
			
		||||
 | 
			
		||||
		// If the original locations or classes were not empty, there's no
 | 
			
		||||
		// need to bother with default detection checks; just let the
 | 
			
		||||
		// appropriate loader process the configuration.
 | 
			
		||||
		if (configAttributes.hasLocations()) {
 | 
			
		||||
			delegateProcessing(xmlLoader, configAttributes);
 | 
			
		||||
		} else if (configAttributes.hasClasses()) {
 | 
			
		||||
			delegateProcessing(annotationConfigLoader, configAttributes);
 | 
			
		||||
		} else {
 | 
			
		||||
			// Else attempt to detect defaults...
 | 
			
		||||
 | 
			
		||||
			// Let the XML loader process the configuration.
 | 
			
		||||
			delegateProcessing(xmlLoader, configAttributes);
 | 
			
		||||
			boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
 | 
			
		||||
 | 
			
		||||
			if (xmlLoaderDetectedDefaults) {
 | 
			
		||||
				if (logger.isInfoEnabled()) {
 | 
			
		||||
					logger.info(String.format("%s detected default locations for context configuration %s.",
 | 
			
		||||
						name(xmlLoader), configAttributes));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasClasses()) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"%s should NOT have detected default configuration classes for context configuration %s.",
 | 
			
		||||
					name(xmlLoader), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Now let the annotation config loader process the configuration.
 | 
			
		||||
			delegateProcessing(annotationConfigLoader, configAttributes);
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasClasses()) {
 | 
			
		||||
				if (logger.isInfoEnabled()) {
 | 
			
		||||
					logger.info(String.format(
 | 
			
		||||
						"%s detected default configuration classes for context configuration %s.",
 | 
			
		||||
						name(annotationConfigLoader), configAttributes));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"%s should NOT have detected default locations for context configuration %s.",
 | 
			
		||||
					name(annotationConfigLoader), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If neither loader detected defaults and no initializers were declared,
 | 
			
		||||
			// throw an exception.
 | 
			
		||||
			if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers "
 | 
			
		||||
							+ "were declared for context configuration %s", name(xmlLoader),
 | 
			
		||||
					name(annotationConfigLoader), configAttributes));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
 | 
			
		||||
				String message = String.format(
 | 
			
		||||
					"Configuration error: both default locations AND default configuration classes "
 | 
			
		||||
							+ "were detected for context configuration %s; configure one or the other, but not both.",
 | 
			
		||||
					configAttributes);
 | 
			
		||||
				logger.error(message);
 | 
			
		||||
				throw new IllegalStateException(message);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delegates to an appropriate candidate {@code SmartContextLoader} to load
 | 
			
		||||
	 * an {@link ApplicationContext}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <p>Delegation is based on explicit knowledge of the implementations of
 | 
			
		||||
	 * {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
 | 
			
		||||
	 * Specifically, the delegation algorithm is as follows:
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <ul>
 | 
			
		||||
	 * <li>If the resource locations in the supplied {@code MergedContextConfiguration}
 | 
			
		||||
	 * are not empty and the annotated classes are empty,
 | 
			
		||||
	 * {@code GenericXmlContextLoader} will load the {@code ApplicationContext}.</li>
 | 
			
		||||
	 * <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
 | 
			
		||||
	 * are not empty and the resource locations are empty,
 | 
			
		||||
	 * {@code AnnotationConfigContextLoader} will load the {@code ApplicationContext}.</li>
 | 
			
		||||
	 * </ul>
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param mergedConfig the merged context configuration to use to load the application context
 | 
			
		||||
	 * @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
 | 
			
		||||
	 * @throws IllegalStateException if neither candidate loader is capable of loading an
 | 
			
		||||
	 * {@code ApplicationContext} from the supplied merged context configuration
 | 
			
		||||
	 */
 | 
			
		||||
	public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
 | 
			
		||||
		Assert.notNull(mergedConfig, "mergedConfig must not be null");
 | 
			
		||||
 | 
			
		||||
		List<SmartContextLoader> candidates = Arrays.asList(xmlLoader, annotationConfigLoader);
 | 
			
		||||
 | 
			
		||||
		for (SmartContextLoader loader : candidates) {
 | 
			
		||||
			// Determine if each loader can load a context from the mergedConfig. If it
 | 
			
		||||
			// can, let it; otherwise, keep iterating.
 | 
			
		||||
			if (supports(loader, mergedConfig)) {
 | 
			
		||||
				return delegateLoading(loader, mergedConfig);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If neither of the candidates supports the mergedConfig based on resources but
 | 
			
		||||
		// ACIs were declared, then delegate to the ACCL.
 | 
			
		||||
		if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
 | 
			
		||||
			return delegateLoading(annotationConfigLoader, mergedConfig);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		throw new IllegalStateException(String.format(
 | 
			
		||||
			"Neither %s nor %s was able to load an ApplicationContext from %s.", name(xmlLoader),
 | 
			
		||||
			name(annotationConfigLoader), mergedConfig));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// --- ContextLoader -------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code DelegatingSmartContextLoader} does not support the
 | 
			
		||||
	 * {@link ContextLoader#processLocations(Class, String...)} method. Call
 | 
			
		||||
	 * {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	public String[] processLocations(Class<?> clazz, String... locations) {
 | 
			
		||||
		throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
 | 
			
		||||
				+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@code DelegatingSmartContextLoader} does not support the
 | 
			
		||||
	 * {@link ContextLoader#loadContext(String...) } method. Call
 | 
			
		||||
	 * {@link #loadContext(MergedContextConfiguration)} instead.
 | 
			
		||||
	 * @throws UnsupportedOperationException
 | 
			
		||||
	 */
 | 
			
		||||
	public ApplicationContext loadContext(String... locations) throws Exception {
 | 
			
		||||
		throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
 | 
			
		||||
				+ "Call loadContext(MergedContextConfiguration) instead.");
 | 
			
		||||
	protected SmartContextLoader getAnnotationConfigLoader() {
 | 
			
		||||
		return this.annotationConfigLoader;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import org.springframework.test.context.SmartContextLoader;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@code WebDelegatingSmartContextLoader} is a concrete implementation of
 | 
			
		||||
 * {@link AbstractDelegatingSmartContextLoader} that delegates to an
 | 
			
		||||
 * {@link XmlWebContextLoader} and an {@link AnnotationConfigWebContextLoader}.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 * @see SmartContextLoader
 | 
			
		||||
 * @see AbstractDelegatingSmartContextLoader
 | 
			
		||||
 * @see XmlWebContextLoader
 | 
			
		||||
 * @see AnnotationConfigWebContextLoader
 | 
			
		||||
 */
 | 
			
		||||
public class WebDelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
 | 
			
		||||
 | 
			
		||||
	private final SmartContextLoader xmlLoader = new XmlWebContextLoader();
 | 
			
		||||
	private final SmartContextLoader annotationConfigLoader = new AnnotationConfigWebContextLoader();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	protected SmartContextLoader getXmlLoader() {
 | 
			
		||||
		return this.xmlLoader;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected SmartContextLoader getAnnotationConfigLoader() {
 | 
			
		||||
		return this.annotationConfigLoader;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.support;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
 | 
			
		||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
 | 
			
		||||
import org.springframework.web.context.support.GenericWebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document XmlWebContextLoader.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
public class XmlWebContextLoader extends AbstractGenericWebContextLoader {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns "<code>-context.xml</code>".
 | 
			
		||||
	 */
 | 
			
		||||
	protected String getResourceSuffix() {
 | 
			
		||||
		return "-context.xml";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden loadBeanDefinitions().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.support.AbstractGenericWebContextLoader#loadBeanDefinitions(org.springframework.web.context.support.GenericWebApplicationContext, org.springframework.test.context.web.WebMergedContextConfiguration)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void loadBeanDefinitions(GenericWebApplicationContext context,
 | 
			
		||||
			WebMergedContextConfiguration webMergedConfig) {
 | 
			
		||||
		new XmlBeanDefinitionReader(context).loadBeanDefinitions(webMergedConfig.getLocations());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.Documented;
 | 
			
		||||
import java.lang.annotation.ElementType;
 | 
			
		||||
import java.lang.annotation.Inherited;
 | 
			
		||||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.RetentionPolicy;
 | 
			
		||||
import java.lang.annotation.Target;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document WebAppConfiguration.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@Documented
 | 
			
		||||
@Inherited
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
@Target(ElementType.TYPE)
 | 
			
		||||
public @interface WebAppConfiguration {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The root directory of the web application (i.e., WAR); should not end with a slash.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * <p>Defaults to {@code "src/main/webapp"}.
 | 
			
		||||
	 */
 | 
			
		||||
	String value() default "src/main/webapp";
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,122 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.ApplicationContextInitializer;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.core.style.ToStringCreator;
 | 
			
		||||
import org.springframework.test.context.ContextLoader;
 | 
			
		||||
import org.springframework.test.context.MergedContextConfiguration;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document WebMergedContextConfiguration.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
public class WebMergedContextConfiguration extends MergedContextConfiguration {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 7323361588604247458L;
 | 
			
		||||
 | 
			
		||||
	private final String resourceBasePath;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document WebMergedContextConfiguration constructor.
 | 
			
		||||
	 */
 | 
			
		||||
	public WebMergedContextConfiguration(
 | 
			
		||||
			Class<?> testClass,
 | 
			
		||||
			String[] locations,
 | 
			
		||||
			Class<?>[] classes,
 | 
			
		||||
			Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
 | 
			
		||||
			String[] activeProfiles, String resourceBasePath, ContextLoader contextLoader) {
 | 
			
		||||
 | 
			
		||||
		super(testClass, locations, classes, contextInitializerClasses, activeProfiles, contextLoader);
 | 
			
		||||
 | 
			
		||||
		this.resourceBasePath = !StringUtils.hasText(resourceBasePath) ? "" : resourceBasePath;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document getResourceBasePath().
 | 
			
		||||
	 */
 | 
			
		||||
	public String getResourceBasePath() {
 | 
			
		||||
		return this.resourceBasePath;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Generate a unique hash code for all properties of this
 | 
			
		||||
	 * {@code WebMergedContextConfiguration} excluding the
 | 
			
		||||
	 * {@linkplain #getTestClass() test class}.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public int hashCode() {
 | 
			
		||||
		final int prime = 31;
 | 
			
		||||
		int result = super.hashCode();
 | 
			
		||||
		result = prime * result + resourceBasePath.hashCode();
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Determine if the supplied object is equal to this {@code WebMergedContextConfiguration}
 | 
			
		||||
	 * instance by comparing both object's {@linkplain #getLocations() locations},
 | 
			
		||||
	 * {@linkplain #getClasses() annotated classes},
 | 
			
		||||
	 * {@linkplain #getContextInitializerClasses() context initializer classes},
 | 
			
		||||
	 * {@linkplain #getActiveProfiles() active profiles}, 
 | 
			
		||||
	 * {@linkplain #getResourceBasePath() resource base path}, and the fully
 | 
			
		||||
	 * qualified names of their {@link #getContextLoader() ContextLoaders}.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean equals(Object obj) {
 | 
			
		||||
 | 
			
		||||
		if (this == obj) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(obj instanceof WebMergedContextConfiguration)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		final WebMergedContextConfiguration that = (WebMergedContextConfiguration) obj;
 | 
			
		||||
 | 
			
		||||
		return super.equals(that) && this.getResourceBasePath().equals(that.getResourceBasePath());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Provide a String representation of the {@linkplain #getTestClass() test class},
 | 
			
		||||
	 * {@linkplain #getLocations() locations}, {@linkplain #getClasses() annotated classes},
 | 
			
		||||
	 * {@linkplain #getContextInitializerClasses() context initializer classes},
 | 
			
		||||
	 * {@linkplain #getActiveProfiles() active profiles},
 | 
			
		||||
	 * {@linkplain #getResourceBasePath() resource base path}, and the name of the
 | 
			
		||||
	 * {@link #getContextLoader() ContextLoader}.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return new ToStringCreator(this)//
 | 
			
		||||
		.append("testClass", getTestClass())//
 | 
			
		||||
		.append("locations", ObjectUtils.nullSafeToString(getLocations()))//
 | 
			
		||||
		.append("classes", ObjectUtils.nullSafeToString(getClasses()))//
 | 
			
		||||
		.append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses()))//
 | 
			
		||||
		.append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles()))//
 | 
			
		||||
		.append("resourceBasePath", getResourceBasePath())//
 | 
			
		||||
		.append("contextLoader", nullSafeToString(getContextLoader()))//
 | 
			
		||||
		.toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,122 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.ServletContext;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.mock.web.MockHttpServletRequest;
 | 
			
		||||
import org.springframework.mock.web.MockHttpServletResponse;
 | 
			
		||||
import org.springframework.mock.web.MockServletContext;
 | 
			
		||||
import org.springframework.test.context.TestContext;
 | 
			
		||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
import org.springframework.web.context.request.RequestContextHolder;
 | 
			
		||||
import org.springframework.web.context.request.ServletWebRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO [SPR-5243] Document WebTestExecutionListener.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
public class WebTestExecutionListener extends AbstractTestExecutionListener {
 | 
			
		||||
 | 
			
		||||
	private static final Log logger = LogFactory.getLog(WebTestExecutionListener.class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden prepareTestInstance().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.support.AbstractTestExecutionListener#prepareTestInstance(org.springframework.test.context.TestContext)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void prepareTestInstance(TestContext testContext) throws Exception {
 | 
			
		||||
		setUpRequestContextIfNecessary(testContext);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden beforeTestMethod().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.support.AbstractTestExecutionListener#beforeTestMethod(org.springframework.test.context.TestContext)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void beforeTestMethod(TestContext testContext) throws Exception {
 | 
			
		||||
		setUpRequestContextIfNecessary(testContext);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document setUpRequestContext().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param testContext
 | 
			
		||||
	 * @param servletContext
 | 
			
		||||
	 */
 | 
			
		||||
	private void setUpRequestContextIfNecessary(TestContext testContext) {
 | 
			
		||||
 | 
			
		||||
		ApplicationContext context = testContext.getApplicationContext();
 | 
			
		||||
 | 
			
		||||
		if (context instanceof WebApplicationContext) {
 | 
			
		||||
			WebApplicationContext wac = (WebApplicationContext) context;
 | 
			
		||||
			ServletContext servletContext = wac.getServletContext();
 | 
			
		||||
			if (!(servletContext instanceof MockServletContext)) {
 | 
			
		||||
				throw new IllegalStateException(String.format(
 | 
			
		||||
					"The WebApplicationContext for test context %s must be configured with a MockServletContext.",
 | 
			
		||||
					testContext));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (logger.isDebugEnabled()) {
 | 
			
		||||
				logger.debug(String.format(
 | 
			
		||||
					"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.",
 | 
			
		||||
					testContext));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (RequestContextHolder.getRequestAttributes() == null) {
 | 
			
		||||
				MockServletContext mockServletContext = (MockServletContext) servletContext;
 | 
			
		||||
				MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext);
 | 
			
		||||
				MockHttpServletResponse response = new MockHttpServletResponse();
 | 
			
		||||
				ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);
 | 
			
		||||
 | 
			
		||||
				RequestContextHolder.setRequestAttributes(servletWebRequest);
 | 
			
		||||
 | 
			
		||||
				if (wac instanceof ConfigurableApplicationContext) {
 | 
			
		||||
					ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) wac;
 | 
			
		||||
					ConfigurableListableBeanFactory bf = configurableApplicationContext.getBeanFactory();
 | 
			
		||||
					bf.registerResolvableDependency(MockHttpServletResponse.class, response);
 | 
			
		||||
					bf.registerResolvableDependency(ServletWebRequest.class, servletWebRequest);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * TODO [SPR-5243] Document overridden afterTestMethod().
 | 
			
		||||
	 *
 | 
			
		||||
	 * @see org.springframework.test.context.support.AbstractTestExecutionListener#afterTestMethod(org.springframework.test.context.TestContext)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void afterTestMethod(TestContext testContext) throws Exception {
 | 
			
		||||
		if (logger.isDebugEnabled()) {
 | 
			
		||||
			logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
 | 
			
		||||
		}
 | 
			
		||||
		RequestContextHolder.resetRequestAttributes();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ public class TestExecutionListenersTests {
 | 
			
		|||
	@Test
 | 
			
		||||
	public void verifyNumDefaultListenersRegistered() throws Exception {
 | 
			
		||||
		TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
 | 
			
		||||
		assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 3,
 | 
			
		||||
		assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 4,
 | 
			
		||||
			testContextManager.getTestExecutionListeners().size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.ServletContext;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.mock.web.MockHttpServletRequest;
 | 
			
		||||
import org.springframework.mock.web.MockHttpServletResponse;
 | 
			
		||||
import org.springframework.mock.web.MockServletContext;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 | 
			
		||||
import org.springframework.web.context.ServletContextAware;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
import org.springframework.web.context.request.ServletWebRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(SpringJUnit4ClassRunner.class)
 | 
			
		||||
@WebAppConfiguration
 | 
			
		||||
public abstract class AbstractBasicWacTests implements ServletContextAware {
 | 
			
		||||
 | 
			
		||||
	protected ServletContext servletContext;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected WebApplicationContext wac;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected MockServletContext mockServletContext;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected MockHttpServletRequest request;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected MockHttpServletResponse response;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected ServletWebRequest webRequest;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	protected String foo;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public void setServletContext(ServletContext servletContext) {
 | 
			
		||||
		this.servletContext = servletContext;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void basicWacFeatures() throws Exception {
 | 
			
		||||
		assertNotNull("ServletContext should be set in the WAC.", wac.getServletContext());
 | 
			
		||||
 | 
			
		||||
		assertNotNull("ServletContext should have been set via ServletContextAware.", servletContext);
 | 
			
		||||
 | 
			
		||||
		assertNotNull("ServletContext should have been autowired from the WAC.", mockServletContext);
 | 
			
		||||
		assertNotNull("MockHttpServletRequest should have been autowired from the WAC.", request);
 | 
			
		||||
		assertNotNull("MockHttpServletResponse should have been autowired from the WAC.", response);
 | 
			
		||||
		assertNotNull("ServletWebRequest should have been autowired from the WAC.", webRequest);
 | 
			
		||||
 | 
			
		||||
		Object rootWac = mockServletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
 | 
			
		||||
		assertNotNull("Root WAC must be stored in the ServletContext as: "
 | 
			
		||||
				+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWac);
 | 
			
		||||
		assertSame("test WAC and Root WAC in ServletContext must be the same object.", wac, rootWac);
 | 
			
		||||
		assertSame("ServletContext instances must be the same object.", mockServletContext, wac.getServletContext());
 | 
			
		||||
		assertSame("ServletContext in the WAC and in the mock request", mockServletContext, request.getServletContext());
 | 
			
		||||
 | 
			
		||||
		assertEquals("Getting real path for ServletContext resource.",
 | 
			
		||||
			new File("src/main/webapp/index.jsp").getCanonicalPath(), mockServletContext.getRealPath("index.jsp"));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@ContextConfiguration
 | 
			
		||||
public class BasicAnnotationConfigWacTests extends AbstractBasicWacTests {
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	static class Config {
 | 
			
		||||
 | 
			
		||||
		@Bean
 | 
			
		||||
		public String foo() {
 | 
			
		||||
			return "enigma";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void fooEnigmaAutowired() {
 | 
			
		||||
		assertEquals("enigma", foo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,12 +13,24 @@
 | 
			
		|||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package org.springframework.test.web.mock.servlet.samples.context;
 | 
			
		||||
 | 
			
		||||
class WebContextLoader extends GenericWebContextLoader {
 | 
			
		||||
package org.springframework.test.context.web;
 | 
			
		||||
 | 
			
		||||
	public WebContextLoader() {
 | 
			
		||||
		super("src/test/resources/META-INF/web-resources", false);
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@ContextConfiguration
 | 
			
		||||
public class BasicXmlWacTests extends AbstractBasicWacTests {
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void fooBarAutowired() {
 | 
			
		||||
		assertEquals("bar", foo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.test.context.web;
 | 
			
		||||
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
import org.junit.runners.Suite.SuiteClasses;
 | 
			
		||||
import org.springframework.test.context.ContextLoader;
 | 
			
		||||
import org.springframework.web.context.WebApplicationContext;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convenience test suite for integration tests that verify support for
 | 
			
		||||
 * {@link WebApplicationContext} {@linkplain ContextLoader context loaders}
 | 
			
		||||
 * in the TestContext framework.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sam Brannen
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(Suite.class)
 | 
			
		||||
// Note: the following 'multi-line' layout is for enhanced code readability.
 | 
			
		||||
@SuiteClasses({//
 | 
			
		||||
	BasicXmlWacTests.class,//
 | 
			
		||||
	BasicAnnotationConfigWacTests.class //
 | 
			
		||||
})
 | 
			
		||||
public class WebContextLoaderTestSuite {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +45,10 @@
 | 
			
		|||
		<level value="warn" />
 | 
			
		||||
	</logger>
 | 
			
		||||
 | 
			
		||||
	<logger name="org.springframework.test.context.web">
 | 
			
		||||
		<level value="warn" />
 | 
			
		||||
	</logger>
 | 
			
		||||
 | 
			
		||||
	<logger name="org.springframework.test.context">
 | 
			
		||||
		<level value="warn" />
 | 
			
		||||
	</logger>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
	xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 | 
			
		||||
 | 
			
		||||
	<bean id="foo" class="java.lang.String" c:_="bar" />
 | 
			
		||||
 | 
			
		||||
</beans>
 | 
			
		||||
		Loading…
	
		Reference in New Issue