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}