|
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