|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2013 the original author or authors. |
| 2 | + * Copyright 2002-2014 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.test.context;
|
18 | 18 |
|
19 |
| -import org.apache.commons.logging.Log; |
20 |
| -import org.apache.commons.logging.LogFactory; |
21 | 19 | import org.springframework.context.ApplicationContext;
|
22 |
| -import org.springframework.util.Assert; |
| 20 | +import org.springframework.context.ConfigurableApplicationContext; |
| 21 | +import org.springframework.test.annotation.DirtiesContext.HierarchyMode; |
23 | 22 |
|
24 | 23 | /**
|
25 |
| - * {@code CacheAwareContextLoaderDelegate} loads application contexts from |
26 |
| - * {@link MergedContextConfiguration} by delegating to the |
27 |
| - * {@link ContextLoader} configured in the {@code MergedContextConfiguration} |
28 |
| - * and interacting transparently with the {@link ContextCache} behind the scenes. |
| 24 | + * A {@code CacheAwareContextLoaderDelegate} is responsible for {@linkplain |
| 25 | + * #loadContext loading} and {@linkplain #closeContext closing} application |
| 26 | + * contexts, interacting transparently with a <em>context cache</em> behind |
| 27 | + * the scenes. |
29 | 28 | *
|
30 |
| - * <p>Note: {@code CacheAwareContextLoaderDelegate} does not implement the |
| 29 | + * <p>Note: {@code CacheAwareContextLoaderDelegate} does not extend the |
31 | 30 | * {@link ContextLoader} or {@link SmartContextLoader} interface.
|
32 | 31 | *
|
33 | 32 | * @author Sam Brannen
|
34 | 33 | * @since 3.2.2
|
35 | 34 | */
|
36 |
| -public class CacheAwareContextLoaderDelegate { |
37 |
| - |
38 |
| - private static final Log logger = LogFactory.getLog(CacheAwareContextLoaderDelegate.class); |
39 |
| - |
40 |
| - private final ContextCache contextCache; |
41 |
| - |
42 |
| - |
43 |
| - CacheAwareContextLoaderDelegate(ContextCache contextCache) { |
44 |
| - Assert.notNull(contextCache, "ContextCache must not be null"); |
45 |
| - this.contextCache = contextCache; |
46 |
| - } |
| 35 | +public interface CacheAwareContextLoaderDelegate { |
47 | 36 |
|
48 | 37 | /**
|
49 |
| - * Load the {@code ApplicationContext} for the supplied merged context |
50 |
| - * configuration. Supports both the {@link SmartContextLoader} and |
51 |
| - * {@link ContextLoader} SPIs. |
52 |
| - * @throws Exception if an error occurs while loading the application context |
53 |
| - */ |
54 |
| - private ApplicationContext loadContextInternal(MergedContextConfiguration mergedContextConfiguration) |
55 |
| - throws Exception { |
56 |
| - ContextLoader contextLoader = mergedContextConfiguration.getContextLoader(); |
57 |
| - Assert.notNull(contextLoader, "Cannot load an ApplicationContext with a NULL 'contextLoader'. " |
58 |
| - + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); |
59 |
| - |
60 |
| - ApplicationContext applicationContext; |
61 |
| - |
62 |
| - if (contextLoader instanceof SmartContextLoader) { |
63 |
| - SmartContextLoader smartContextLoader = (SmartContextLoader) contextLoader; |
64 |
| - applicationContext = smartContextLoader.loadContext(mergedContextConfiguration); |
65 |
| - } |
66 |
| - else { |
67 |
| - String[] locations = mergedContextConfiguration.getLocations(); |
68 |
| - Assert.notNull(locations, "Cannot load an ApplicationContext with a NULL 'locations' array. " |
69 |
| - + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); |
70 |
| - applicationContext = contextLoader.loadContext(locations); |
71 |
| - } |
72 |
| - |
73 |
| - return applicationContext; |
74 |
| - } |
75 |
| - |
76 |
| - /** |
77 |
| - * Load the {@link ApplicationContext application context} for the supplied |
78 |
| - * merged context configuration. |
| 38 | + * Load the {@linkplain ApplicationContext application context} for the supplied |
| 39 | + * {@link MergedContextConfiguration} by delegating to the {@link ContextLoader} |
| 40 | + * configured in the given {@code MergedContextConfiguration}. |
| 41 | + * |
| 42 | + * <p>If the context is present in the <em>context cache</em> it will simply |
| 43 | + * be returned; otherwise, it will be loaded, stored in the cache, and returned. |
79 | 44 | *
|
80 |
| - * <p>If the context is present in the cache it will simply be returned; |
81 |
| - * otherwise, it will be loaded, stored in the cache, and returned. |
| 45 | + * @param mergedContextConfiguration the merged context configuration to use |
| 46 | + * to load the application context; never {@code null} |
82 | 47 | * @return the application context
|
83 | 48 | * @throws IllegalStateException if an error occurs while retrieving or
|
84 | 49 | * loading the application context
|
85 | 50 | */
|
86 |
| - public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) { |
87 |
| - synchronized (contextCache) { |
88 |
| - ApplicationContext context = contextCache.get(mergedContextConfiguration); |
89 |
| - if (context == null) { |
90 |
| - try { |
91 |
| - context = loadContextInternal(mergedContextConfiguration); |
92 |
| - if (logger.isDebugEnabled()) { |
93 |
| - logger.debug(String.format("Storing ApplicationContext in cache under key [%s].", |
94 |
| - mergedContextConfiguration)); |
95 |
| - } |
96 |
| - contextCache.put(mergedContextConfiguration, context); |
97 |
| - } |
98 |
| - catch (Exception ex) { |
99 |
| - throw new IllegalStateException("Failed to load ApplicationContext", ex); |
100 |
| - } |
101 |
| - } |
102 |
| - else { |
103 |
| - if (logger.isDebugEnabled()) { |
104 |
| - logger.debug(String.format("Retrieved ApplicationContext from cache with key [%s].", |
105 |
| - mergedContextConfiguration)); |
106 |
| - } |
107 |
| - } |
108 |
| - return context; |
109 |
| - } |
110 |
| - } |
| 51 | + ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration); |
| 52 | + |
| 53 | + /** |
| 54 | + * Remove the {@linkplain ApplicationContext application context} for the |
| 55 | + * supplied {@link MergedContextConfiguration} from the <em>context cache</em> |
| 56 | + * and {@linkplain ConfigurableApplicationContext#close() close} it if it is |
| 57 | + * an instance of {@link ConfigurableApplicationContext}. |
| 58 | + * |
| 59 | + * <p>The semantics of the supplied {@code HierarchyMode} must be honored when |
| 60 | + * removing the context from the cache. See the Javadoc for {@link HierarchyMode} |
| 61 | + * for details. |
| 62 | + * |
| 63 | + * <p>Generally speaking, this method should only be called if the state of |
| 64 | + * a singleton bean has been changed (potentially affecting future interaction |
| 65 | + * with the context) or if the context needs to be prematurely removed from |
| 66 | + * the cache. |
| 67 | + * |
| 68 | + * @param mergedContextConfiguration the merged context configuration for the |
| 69 | + * application context to close; never {@code null} |
| 70 | + * @param hierarchyMode the hierarchy mode; may be {@code null} if the context |
| 71 | + * is not part of a hierarchy |
| 72 | + * @since 4.1 |
| 73 | + */ |
| 74 | + void closeContext(MergedContextConfiguration mergedContextConfiguration, HierarchyMode hierarchyMode); |
111 | 75 |
|
112 | 76 | }
|
0 commit comments