001/*
002 * Copyright 2002-2019 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.web.context.support;
018
019import javax.servlet.ServletConfig;
020import javax.servlet.ServletContext;
021
022import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
023import org.springframework.beans.factory.support.DefaultListableBeanFactory;
024import org.springframework.context.support.GenericApplicationContext;
025import org.springframework.core.env.ConfigurableEnvironment;
026import org.springframework.core.io.Resource;
027import org.springframework.core.io.support.ResourcePatternResolver;
028import org.springframework.lang.Nullable;
029import org.springframework.ui.context.Theme;
030import org.springframework.ui.context.ThemeSource;
031import org.springframework.ui.context.support.UiApplicationContextUtils;
032import org.springframework.util.Assert;
033import org.springframework.util.ObjectUtils;
034import org.springframework.util.StringUtils;
035import org.springframework.web.context.ConfigurableWebApplicationContext;
036import org.springframework.web.context.ConfigurableWebEnvironment;
037import org.springframework.web.context.ServletContextAware;
038
039/**
040 * Subclass of {@link GenericApplicationContext}, suitable for web environments.
041 *
042 * <p>Implements {@link org.springframework.web.context.ConfigurableWebApplicationContext},
043 * but is not intended for declarative setup in {@code web.xml}. Instead, it is designed
044 * for programmatic setup, for example for building nested contexts or for use within
045 * {@link org.springframework.web.WebApplicationInitializer WebApplicationInitializers}.
046 *
047 * <p><b>If you intend to implement a WebApplicationContext that reads bean definitions
048 * from configuration files, consider deriving from AbstractRefreshableWebApplicationContext,
049 * reading the bean definitions in an implementation of the {@code loadBeanDefinitions}
050 * method.</b>
051 *
052 * <p>Interprets resource paths as servlet context resources, i.e. as paths beneath
053 * the web application root. Absolute paths, e.g. for files outside the web app root,
054 * can be accessed via "file:" URLs, as implemented by AbstractApplicationContext.
055 *
056 * <p>In addition to the special beans detected by
057 * {@link org.springframework.context.support.AbstractApplicationContext},
058 * this class detects a ThemeSource bean in the context, with the name "themeSource".
059 *
060 * @author Juergen Hoeller
061 * @author Chris Beams
062 * @since 1.2
063 */
064public class GenericWebApplicationContext extends GenericApplicationContext
065                implements ConfigurableWebApplicationContext, ThemeSource {
066
067        @Nullable
068        private ServletContext servletContext;
069
070        @Nullable
071        private ThemeSource themeSource;
072
073
074        /**
075         * Create a new GenericWebApplicationContext.
076         * @see #setServletContext
077         * @see #registerBeanDefinition
078         * @see #refresh
079         */
080        public GenericWebApplicationContext() {
081                super();
082        }
083
084        /**
085         * Create a new GenericWebApplicationContext for the given ServletContext.
086         * @param servletContext the ServletContext to run in
087         * @see #registerBeanDefinition
088         * @see #refresh
089         */
090        public GenericWebApplicationContext(ServletContext servletContext) {
091                this.servletContext = servletContext;
092        }
093
094        /**
095         * Create a new GenericWebApplicationContext with the given DefaultListableBeanFactory.
096         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
097         * @see #setServletContext
098         * @see #registerBeanDefinition
099         * @see #refresh
100         */
101        public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory) {
102                super(beanFactory);
103        }
104
105        /**
106         * Create a new GenericWebApplicationContext with the given DefaultListableBeanFactory.
107         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
108         * @param servletContext the ServletContext to run in
109         * @see #registerBeanDefinition
110         * @see #refresh
111         */
112        public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory, ServletContext servletContext) {
113                super(beanFactory);
114                this.servletContext = servletContext;
115        }
116
117
118        /**
119         * Set the ServletContext that this WebApplicationContext runs in.
120         */
121        @Override
122        public void setServletContext(@Nullable ServletContext servletContext) {
123                this.servletContext = servletContext;
124        }
125
126        @Override
127        @Nullable
128        public ServletContext getServletContext() {
129                return this.servletContext;
130        }
131
132        @Override
133        public String getApplicationName() {
134                return (this.servletContext != null ? this.servletContext.getContextPath() : "");
135        }
136
137        /**
138         * Create and return a new {@link StandardServletEnvironment}.
139         */
140        @Override
141        protected ConfigurableEnvironment createEnvironment() {
142                return new StandardServletEnvironment();
143        }
144
145        /**
146         * Register ServletContextAwareProcessor.
147         * @see ServletContextAwareProcessor
148         */
149        @Override
150        protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
151                if (this.servletContext != null) {
152                        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
153                        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
154                }
155                WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
156                WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
157        }
158
159        /**
160         * This implementation supports file paths beneath the root of the ServletContext.
161         * @see ServletContextResource
162         */
163        @Override
164        protected Resource getResourceByPath(String path) {
165                Assert.state(this.servletContext != null, "No ServletContext available");
166                return new ServletContextResource(this.servletContext, path);
167        }
168
169        /**
170         * This implementation supports pattern matching in unexpanded WARs too.
171         * @see ServletContextResourcePatternResolver
172         */
173        @Override
174        protected ResourcePatternResolver getResourcePatternResolver() {
175                return new ServletContextResourcePatternResolver(this);
176        }
177
178        /**
179         * Initialize the theme capability.
180         */
181        @Override
182        protected void onRefresh() {
183                this.themeSource = UiApplicationContextUtils.initThemeSource(this);
184        }
185
186        /**
187         * {@inheritDoc}
188         * <p>Replace {@code Servlet}-related property sources.
189         */
190        @Override
191        protected void initPropertySources() {
192                ConfigurableEnvironment env = getEnvironment();
193                if (env instanceof ConfigurableWebEnvironment) {
194                        ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
195                }
196        }
197
198        @Override
199        @Nullable
200        public Theme getTheme(String themeName) {
201                Assert.state(this.themeSource != null, "No ThemeSource available");
202                return this.themeSource.getTheme(themeName);
203        }
204
205
206        // ---------------------------------------------------------------------
207        // Pseudo-implementation of ConfigurableWebApplicationContext
208        // ---------------------------------------------------------------------
209
210        @Override
211        public void setServletConfig(@Nullable ServletConfig servletConfig) {
212                // no-op
213        }
214
215        @Override
216        @Nullable
217        public ServletConfig getServletConfig() {
218                throw new UnsupportedOperationException(
219                                "GenericWebApplicationContext does not support getServletConfig()");
220        }
221
222        @Override
223        public void setNamespace(@Nullable String namespace) {
224                // no-op
225        }
226
227        @Override
228        @Nullable
229        public String getNamespace() {
230                throw new UnsupportedOperationException(
231                                "GenericWebApplicationContext does not support getNamespace()");
232        }
233
234        @Override
235        public void setConfigLocation(String configLocation) {
236                if (StringUtils.hasText(configLocation)) {
237                        throw new UnsupportedOperationException(
238                                        "GenericWebApplicationContext does not support setConfigLocation(). " +
239                                        "Do you still have an 'contextConfigLocations' init-param set?");
240                }
241        }
242
243        @Override
244        public void setConfigLocations(String... configLocations) {
245                if (!ObjectUtils.isEmpty(configLocations)) {
246                        throw new UnsupportedOperationException(
247                                        "GenericWebApplicationContext does not support setConfigLocations(). " +
248                                        "Do you still have an 'contextConfigLocations' init-param set?");
249                }
250        }
251
252        @Override
253        public String[] getConfigLocations() {
254                throw new UnsupportedOperationException(
255                                "GenericWebApplicationContext does not support getConfigLocations()");
256        }
257
258}