001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.test;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021:
022: import org.springframework.context.ConfigurableApplicationContext;
023: import org.springframework.util.Assert;
024: import org.springframework.util.ObjectUtils;
025:
026: /**
027: * Superclass for JUnit test cases using Spring
028: * {@link org.springframework.context.ApplicationContext ApplicationContexts}.
029: *
030: * <p>Maintains a static cache of contexts by key. This has significant performance
031: * benefit if initializing the context would take time. While initializing a
032: * Spring context itself is very quick, some beans in a context, such as
033: * a LocalSessionFactoryBean for working with Hibernate, may take some time
034: * to initialize. Hence it often makes sense to do that initializing once.
035: *
036: * <p>Any ApplicationContext created by this class will be asked to register a JVM
037: * shutdown hook for itself. Unless the context gets closed early, all context
038: * instances will be automatically closed on JVM shutdown. This allows for freeing
039: * external resources held by beans within the context, e.g. temporary files.
040: *
041: * <p>Normally you won't extend this class directly but rather extend one of
042: * its subclasses.
043: *
044: * @author Rod Johnson
045: * @author Juergen Hoeller
046: * @since 1.1.1
047: * @see AbstractDependencyInjectionSpringContextTests
048: * @see AbstractTransactionalSpringContextTests
049: * @see AbstractTransactionalDataSourceSpringContextTests
050: */
051: public abstract class AbstractSpringContextTests extends
052: ConditionalTestCase {
053:
054: /**
055: * Map of context keys returned by subclasses of this class, to
056: * Spring contexts. This needs to be static, as JUnit tests are
057: * destroyed and recreated between running individual test methods.
058: */
059: private static Map contextKeyToContextMap = new HashMap();
060:
061: /**
062: * Default constructor for AbstractSpringContextTests.
063: */
064: public AbstractSpringContextTests() {
065: }
066:
067: /**
068: * Constructor for AbstractSpringContextTests with a JUnit name.
069: */
070: public AbstractSpringContextTests(String name) {
071: super (name);
072: }
073:
074: /**
075: * Explicitly add an ApplicationContext instance under a given key.
076: * <p>This is not meant to be used by subclasses. It is rather exposed
077: * for special test suite environments.
078: * @param key the context key
079: * @param context the ApplicationContext instance
080: */
081: public final void addContext(Object key,
082: ConfigurableApplicationContext context) {
083: Assert.notNull(context, "ApplicationContext must not be null");
084: contextKeyToContextMap.put(contextKeyString(key), context);
085: }
086:
087: /**
088: * Return whether there is a cached context for the given key.
089: * @param contextKey the context key
090: */
091: protected final boolean hasCachedContext(Object contextKey) {
092: return contextKeyToContextMap.containsKey(contextKey);
093: }
094:
095: /**
096: * Obtain an ApplicationContext for the given key, potentially cached.
097: * @param key the context key
098: * @return the corresponding ApplicationContext instance (potentially cached)
099: */
100: protected final ConfigurableApplicationContext getContext(Object key)
101: throws Exception {
102: String keyString = contextKeyString(key);
103: ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) contextKeyToContextMap
104: .get(keyString);
105: if (ctx == null) {
106: ctx = loadContext(key);
107: ctx.registerShutdownHook();
108: contextKeyToContextMap.put(keyString, ctx);
109: }
110: return ctx;
111: }
112:
113: /**
114: * Mark the context with the given key as dirty. This will cause the
115: * cached context to be reloaded before the next test case is executed.
116: * <p>Call this method only if you change the state of a singleton
117: * bean, potentially affecting future tests.
118: */
119: protected final void setDirty(Object contextKey) {
120: String keyString = contextKeyString(contextKey);
121: ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) contextKeyToContextMap
122: .remove(keyString);
123: if (ctx != null) {
124: ctx.close();
125: }
126: }
127:
128: /**
129: * Subclasses can override this to return a String representation of
130: * their context key for use in logging.
131: * @param contextKey the context key
132: */
133: protected String contextKeyString(Object contextKey) {
134: return ObjectUtils.nullSafeToString(contextKey);
135: }
136:
137: /**
138: * Load a new ApplicationContext for the given key.
139: * <p>To be implemented by subclasses.
140: * @param key the context key
141: * @return the corresponding ApplicationContext instance (new)
142: */
143: protected abstract ConfigurableApplicationContext loadContext(
144: Object key) throws Exception;
145:
146: }
|