diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java b/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java index e9078111ef..372b617be0 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java @@ -50,7 +50,9 @@ 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.GenericXmlContextLoader"; + // private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = + // "org.springframework.test.context.support.GenericXmlContextLoader"; + private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader"; private ContextLoaderUtils() { diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java new file mode 100644 index 0000000000..8e4de5d399 --- /dev/null +++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java @@ -0,0 +1,143 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.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.ContextConfigurationAttributes; +import org.springframework.test.context.ContextLoader; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.SmartContextLoader; + +/** + * TODO Document DelegatingSmartContextLoader. + * + * @author Sam Brannen + * @since 3.1 + * @see SmartContextLoader + * @see GenericXmlContextLoader + * @see AnnotationConfigContextLoader + */ +public class DelegatingSmartContextLoader implements SmartContextLoader { + + private static final Log logger = LogFactory.getLog(DelegatingSmartContextLoader.class); + + private final List candidates = Arrays.asList(new GenericXmlContextLoader(), + new AnnotationConfigContextLoader()); + + + // --- SmartContextLoader -------------------------------------------------- + + /** + * TODO Document generatesDefaults() implementation. + */ + public boolean generatesDefaults() { + for (SmartContextLoader loader : candidates) { + if (loader.generatesDefaults()) { + return true; + } + } + return false; + } + + /** + * TODO Document processContextConfiguration() implementation. + */ + public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { + for (SmartContextLoader loader : candidates) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Delegating to loader [%s] to process context configuration [%s].", + loader.getClass().getName(), configAttributes)); + } + + // TODO Implement processContextConfiguration(). + // + // If the original locations and classes are not empty, there's no + // need to bother with default generation checks; just let each + // loader process the configuration. + // + // Otherwise, if a loader claims to generate defaults, let it + // process the configuration, and then verify that it actually did + // generate defaults. + // + // If it generated defaults, there's no need to delegate to + // additional candidates. So: + // 1) stop iterating + // 2) mark the current loader as the winning candidate (?) + // 3) log an info message. + + loader.processContextConfiguration(configAttributes); + } + } + + /** + * TODO Document loadContext(MergedContextConfiguration) implementation. + */ + public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + + for (SmartContextLoader loader : candidates) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Delegating to loader [%s] to load context from [%s].", + loader.getClass().getName(), mergedConfig)); + } + + // TODO Implement loadContext(MergedContextConfiguration). + // + // Ask each loader if it _can_ load a context from the mergedConfig. + // If a loader can, let it; otherwise, continue iterating over all + // remaining candidates. + // + // If no candidate can load a context from the mergedConfig, throw + // an exception. + } + + // TODO Implement delegation logic. + // + // Proof of concept: ensuring that hard-coded delegation to + // GenericXmlContextLoader works "as is". + return candidates.get(0).loadContext(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 API. " + + "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 API. " + + "Call loadContext(MergedContextConfiguration) instead."); + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java index 8f1df7e3fc..1e5fb33b2a 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java @@ -27,8 +27,8 @@ import java.util.List; import org.junit.Test; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.test.context.support.DelegatingSmartContextLoader; import org.springframework.test.context.support.GenericPropertiesContextLoader; -import org.springframework.test.context.support.GenericXmlContextLoader; /** * Unit tests for {@link ContextLoaderUtils}. @@ -120,7 +120,7 @@ public class ContextLoaderUtilsTests { mergedConfig, testClass, new String[] { "classpath:/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml" }, - EMPTY_CLASS_ARRAY, GenericXmlContextLoader.class); + EMPTY_CLASS_ARRAY, DelegatingSmartContextLoader.class); } @Test @@ -129,7 +129,7 @@ public class ContextLoaderUtilsTests { MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null); assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" }, - new Class[] { FooConfig.class }, GenericXmlContextLoader.class); + new Class[] { FooConfig.class }, DelegatingSmartContextLoader.class); } @Test