001/*
002 * Copyright 2002-2016 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 *      https://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
017package org.springframework.test.context.web;
018
019import java.util.Set;
020
021import org.springframework.context.ApplicationContextInitializer;
022import org.springframework.context.ConfigurableApplicationContext;
023import org.springframework.core.style.ToStringCreator;
024import org.springframework.test.context.CacheAwareContextLoaderDelegate;
025import org.springframework.test.context.ContextCustomizer;
026import org.springframework.test.context.ContextLoader;
027import org.springframework.test.context.MergedContextConfiguration;
028import org.springframework.util.ObjectUtils;
029import org.springframework.util.StringUtils;
030
031/**
032 * {@code WebMergedContextConfiguration} encapsulates the <em>merged</em>
033 * context configuration declared on a test class and all of its superclasses
034 * via {@link org.springframework.test.context.ContextConfiguration @ContextConfiguration},
035 * {@link WebAppConfiguration @WebAppConfiguration}, and
036 * {@link org.springframework.test.context.ActiveProfiles @ActiveProfiles}.
037 *
038 * <p>{@code WebMergedContextConfiguration} extends the contract of
039 * {@link MergedContextConfiguration} by adding support for the {@link
040 * #getResourceBasePath() resource base path} configured via {@code @WebAppConfiguration}.
041 * This allows the {@link org.springframework.test.context.TestContext TestContext}
042 * to properly cache the corresponding {@link
043 * org.springframework.web.context.WebApplicationContext WebApplicationContext}
044 * that was loaded using properties of this {@code WebMergedContextConfiguration}.
045 *
046 * @author Sam Brannen
047 * @since 3.2
048 * @see WebAppConfiguration
049 * @see MergedContextConfiguration
050 * @see org.springframework.test.context.ContextConfiguration
051 * @see org.springframework.test.context.ActiveProfiles
052 * @see org.springframework.test.context.ContextConfigurationAttributes
053 * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
054 */
055public class WebMergedContextConfiguration extends MergedContextConfiguration {
056
057        private static final long serialVersionUID = 7323361588604247458L;
058
059        private final String resourceBasePath;
060
061
062        /**
063         * Create a new {@code WebMergedContextConfiguration} instance for the
064         * supplied parameters.
065         * <p>Delegates to
066         * {@link #WebMergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], String, ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}.
067         * @param testClass the test class for which the configuration was merged
068         * @param locations the merged resource locations
069         * @param classes the merged annotated classes
070         * @param contextInitializerClasses the merged context initializer classes
071         * @param activeProfiles the merged active bean definition profiles
072         * @param resourceBasePath the resource path to the root directory of the web application
073         * @param contextLoader the resolved {@code ContextLoader}
074         * @param cacheAwareContextLoaderDelegate a cache-aware context loader
075         * delegate with which to retrieve the parent context
076         * @param parent the parent configuration or {@code null} if there is no parent
077         * @since 3.2.2
078         * @deprecated as of Spring 4.1, use
079         * {@link #WebMergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], String, ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}
080         * instead.
081         */
082        @Deprecated
083        public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
084                        Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
085                        String[] activeProfiles, String resourceBasePath, ContextLoader contextLoader,
086                        CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) {
087
088                this(testClass, locations, classes, contextInitializerClasses, activeProfiles, null, null, resourceBasePath,
089                        contextLoader, cacheAwareContextLoaderDelegate, parent);
090        }
091
092        /**
093         * Create a new {@code WebMergedContextConfiguration} instance by copying
094         * all properties from the supplied {@code MergedContextConfiguration}.
095         * <p>If an <em>empty</em> value is supplied for the {@code resourceBasePath}
096         * an empty string will be used.
097         * @param resourceBasePath the resource path to the root directory of the web application
098         * @since 4.1
099         */
100        public WebMergedContextConfiguration(MergedContextConfiguration mergedConfig, String resourceBasePath) {
101                super(mergedConfig);
102                this.resourceBasePath = !StringUtils.hasText(resourceBasePath) ? "" : resourceBasePath;
103        }
104
105        /**
106         * Create a new {@code WebMergedContextConfiguration} instance for the
107         * supplied parameters.
108         * <p>If a {@code null} value is supplied for {@code locations},
109         * {@code classes}, {@code activeProfiles}, {@code propertySourceLocations},
110         * or {@code propertySourceProperties} an empty array will be stored instead.
111         * If a {@code null} value is supplied for the
112         * {@code contextInitializerClasses} an empty set will be stored instead.
113         * If an <em>empty</em> value is supplied for the {@code resourceBasePath}
114         * an empty string will be used. Furthermore, active profiles will be sorted,
115         * and duplicate profiles will be removed.
116         * @param testClass the test class for which the configuration was merged
117         * @param locations the merged resource locations
118         * @param classes the merged annotated classes
119         * @param contextInitializerClasses the merged context initializer classes
120         * @param activeProfiles the merged active bean definition profiles
121         * @param propertySourceLocations the merged {@code PropertySource} locations
122         * @param propertySourceProperties the merged {@code PropertySource} properties
123         * @param resourceBasePath the resource path to the root directory of the web application
124         * @param contextLoader the resolved {@code ContextLoader}
125         * @param cacheAwareContextLoaderDelegate a cache-aware context loader
126         * delegate with which to retrieve the parent context
127         * @param parent the parent configuration or {@code null} if there is no parent
128         * @since 4.1
129         */
130        public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
131                        Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
132                        String[] activeProfiles, String[] propertySourceLocations, String[] propertySourceProperties,
133                        String resourceBasePath, ContextLoader contextLoader,
134                        CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) {
135
136                this(testClass, locations, classes, contextInitializerClasses, activeProfiles, propertySourceLocations,
137                        propertySourceProperties, null, resourceBasePath, contextLoader, cacheAwareContextLoaderDelegate, parent);
138        }
139
140        /**
141         * Create a new {@code WebMergedContextConfiguration} instance for the
142         * supplied parameters.
143         * <p>If a {@code null} value is supplied for {@code locations},
144         * {@code classes}, {@code activeProfiles}, {@code propertySourceLocations},
145         * or {@code propertySourceProperties} an empty array will be stored instead.
146         * If a {@code null} value is supplied for {@code contextInitializerClasses}
147         * or {@code contextCustomizers}, an empty set will be stored instead.
148         * If an <em>empty</em> value is supplied for the {@code resourceBasePath}
149         * an empty string will be used. Furthermore, active profiles will be sorted,
150         * and duplicate profiles will be removed.
151         * @param testClass the test class for which the configuration was merged
152         * @param locations the merged context resource locations
153         * @param classes the merged annotated classes
154         * @param contextInitializerClasses the merged context initializer classes
155         * @param activeProfiles the merged active bean definition profiles
156         * @param propertySourceLocations the merged {@code PropertySource} locations
157         * @param propertySourceProperties the merged {@code PropertySource} properties
158         * @param contextCustomizers the context customizers
159         * @param resourceBasePath the resource path to the root directory of the web application
160         * @param contextLoader the resolved {@code ContextLoader}
161         * @param cacheAwareContextLoaderDelegate a cache-aware context loader
162         * delegate with which to retrieve the parent context
163         * @param parent the parent configuration or {@code null} if there is no parent
164         * @since 4.3
165         */
166        public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
167                        Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
168                        String[] activeProfiles, String[] propertySourceLocations, String[] propertySourceProperties,
169                        Set<ContextCustomizer> contextCustomizers, String resourceBasePath, ContextLoader contextLoader,
170                        CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) {
171
172                super(testClass, locations, classes, contextInitializerClasses, activeProfiles, propertySourceLocations,
173                        propertySourceProperties, contextCustomizers, contextLoader, cacheAwareContextLoaderDelegate, parent);
174
175                this.resourceBasePath = (StringUtils.hasText(resourceBasePath) ? resourceBasePath : "");
176        }
177
178        /**
179         * Get the resource path to the root directory of the web application for the
180         * {@linkplain #getTestClass() test class}, configured via {@code @WebAppConfiguration}.
181         * @see WebAppConfiguration
182         */
183        public String getResourceBasePath() {
184                return this.resourceBasePath;
185        }
186
187
188        /**
189         * Determine if the supplied object is equal to this {@code WebMergedContextConfiguration}
190         * instance by comparing both object's {@linkplain #getLocations() locations},
191         * {@linkplain #getClasses() annotated classes},
192         * {@linkplain #getContextInitializerClasses() context initializer classes},
193         * {@linkplain #getActiveProfiles() active profiles},
194         * {@linkplain #getResourceBasePath() resource base path},
195         * {@linkplain #getParent() parents}, and the fully qualified names of their
196         * {@link #getContextLoader() ContextLoaders}.
197         */
198        @Override
199        public boolean equals(Object other) {
200                return (this == other || (super.equals(other) &&
201                                this.resourceBasePath.equals(((WebMergedContextConfiguration) other).resourceBasePath)));
202        }
203
204        /**
205         * Generate a unique hash code for all properties of this
206         * {@code WebMergedContextConfiguration} excluding the
207         * {@linkplain #getTestClass() test class}.
208         */
209        @Override
210        public int hashCode() {
211                return super.hashCode() * 31 + this.resourceBasePath.hashCode();
212        }
213
214        /**
215         * Provide a String representation of the {@linkplain #getTestClass() test class},
216         * {@linkplain #getLocations() locations}, {@linkplain #getClasses() annotated classes},
217         * {@linkplain #getContextInitializerClasses() context initializer classes},
218         * {@linkplain #getActiveProfiles() active profiles},
219         * {@linkplain #getPropertySourceLocations() property source locations},
220         * {@linkplain #getPropertySourceProperties() property source properties},
221         * {@linkplain #getContextCustomizers() context customizers},
222         * {@linkplain #getResourceBasePath() resource base path}, the name of the
223         * {@link #getContextLoader() ContextLoader}, and the
224         * {@linkplain #getParent() parent configuration}.
225         */
226        @Override
227        public String toString() {
228                return new ToStringCreator(this)
229                                .append("testClass", getTestClass())
230                                .append("locations", ObjectUtils.nullSafeToString(getLocations()))
231                                .append("classes", ObjectUtils.nullSafeToString(getClasses()))
232                                .append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses()))
233                                .append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles()))
234                                .append("propertySourceLocations", ObjectUtils.nullSafeToString(getPropertySourceLocations()))
235                                .append("propertySourceProperties", ObjectUtils.nullSafeToString(getPropertySourceProperties()))
236                                .append("contextCustomizers", getContextCustomizers())
237                                .append("resourceBasePath", getResourceBasePath())
238                                .append("contextLoader", nullSafeToString(getContextLoader()))
239                                .append("parent", getParent())
240                                .toString();
241        }
242
243}