1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.web.context;
  17. import javax.servlet.ServletContext;
  18. import org.apache.commons.logging.Log;
  19. import org.apache.commons.logging.LogFactory;
  20. import org.springframework.beans.BeanUtils;
  21. import org.springframework.beans.BeansException;
  22. import org.springframework.context.ApplicationContext;
  23. import org.springframework.context.ApplicationContextException;
  24. import org.springframework.context.ConfigurableApplicationContext;
  25. import org.springframework.util.StringUtils;
  26. import org.springframework.web.context.support.XmlWebApplicationContext;
  27. /**
  28. * Performs the actual initialization work for the root application context.
  29. * Called by ContextLoaderListener and ContextLoaderServlet.
  30. *
  31. * <p>Regards a "contextClass" parameter at the web.xml context-param level,
  32. * falling back to the default context class (XmlWebApplicationContext) if not found.
  33. * With the default ContextLoader, a context class needs to implement
  34. * ConfigurableWebApplicationContext.
  35. *
  36. * <p>Passes a "contextConfigLocation" context-param to the context instance,
  37. * parsing it into potentially multiple file paths which can be separated by any
  38. * number of commas and spaces, like "applicationContext1.xml, applicationContext2.xml".
  39. * If not explicitly specified, the context implementation is supposed to use a
  40. * default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml").
  41. *
  42. * <p>Note: In case of multiple config locations, later bean definitions will
  43. * override ones defined in earlier loaded files, at least when using one of
  44. * Spring's default ApplicationContext implementations. This can be leveraged
  45. * to deliberately override certain bean definitions via an extra XML file.
  46. *
  47. * @author Juergen Hoeller
  48. * @author Colin Sampaleanu
  49. * @since 17.02.2003
  50. * @see ContextLoaderListener
  51. * @see ContextLoaderServlet
  52. * @see ConfigurableWebApplicationContext
  53. * @see org.springframework.web.context.support.XmlWebApplicationContext
  54. */
  55. public class ContextLoader {
  56. /**
  57. * Config param for the root WebApplicationContext implementation class to use:
  58. * "contextClass"
  59. */
  60. public static final String CONTEXT_CLASS_PARAM = "contextClass";
  61. /**
  62. * Default context class for ContextLoader.
  63. * @see org.springframework.web.context.support.XmlWebApplicationContext
  64. */
  65. public static final Class DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
  66. /**
  67. * Name of servlet context parameter that can specify the config location
  68. * for the root context, falling back to the implementation's default else.
  69. * @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
  70. */
  71. public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
  72. private final Log logger = LogFactory.getLog(ContextLoader.class);
  73. /**
  74. * Initialize Spring's web application context for the given servlet context,
  75. * regarding the "contextClass" and "contextConfigLocation" context-params.
  76. * @param servletContext current servlet context
  77. * @return the new WebApplicationContext
  78. * @throws BeansException if the context couldn't be initialized
  79. * @see #CONTEXT_CLASS_PARAM
  80. * @see #CONFIG_LOCATION_PARAM
  81. */
  82. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws BeansException {
  83. servletContext.log("Loading root WebApplicationContext");
  84. try {
  85. ApplicationContext parent = loadParentContext(servletContext);
  86. WebApplicationContext wac = createWebApplicationContext(servletContext, parent);
  87. logger.info("Using context class [" + wac.getClass().getName() + "] for root WebApplicationContext");
  88. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
  89. if (logger.isInfoEnabled()) {
  90. logger.info("Published root WebApplicationContext [" + wac +
  91. "] as ServletContext attribute with name [" +
  92. WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
  93. }
  94. return wac;
  95. }
  96. catch (RuntimeException ex) {
  97. logger.error("Context initialization failed", ex);
  98. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
  99. throw ex;
  100. }
  101. catch (Error err) {
  102. logger.error("Context initialization failed", err);
  103. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
  104. throw err;
  105. }
  106. }
  107. /**
  108. * Instantiate the root WebApplicationContext for this loader, either a default
  109. * XmlWebApplicationContext or a custom context class if specified.
  110. * This implementation expects custom contexts to implement ConfigurableWebApplicationContext.
  111. * Can be overridden in subclasses.
  112. * @throws BeansException if the context couldn't be initialized
  113. * @see #CONTEXT_CLASS_PARAM
  114. * @see #DEFAULT_CONTEXT_CLASS
  115. * @see ConfigurableWebApplicationContext
  116. * @see org.springframework.web.context.support.XmlWebApplicationContext
  117. */
  118. protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent)
  119. throws BeansException {
  120. String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
  121. Class contextClass = DEFAULT_CONTEXT_CLASS;
  122. if (contextClassName != null) {
  123. try {
  124. contextClass = Class.forName(contextClassName, true, Thread.currentThread().getContextClassLoader());
  125. }
  126. catch (ClassNotFoundException ex) {
  127. throw new ApplicationContextException("Failed to load context class [" + contextClassName + "]", ex);
  128. }
  129. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
  130. throw new ApplicationContextException(
  131. "Custom context class [" + contextClassName + "] is not of type ConfigurableWebApplicationContext");
  132. }
  133. }
  134. ConfigurableWebApplicationContext wac =
  135. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  136. wac.setParent(parent);
  137. wac.setServletContext(servletContext);
  138. String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
  139. if (configLocation != null) {
  140. wac.setConfigLocations(
  141. StringUtils.tokenizeToStringArray(
  142. configLocation, ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS, true, true));
  143. }
  144. wac.refresh();
  145. return wac;
  146. }
  147. /**
  148. * Template method which may be overridden by a subclass to load or obtain
  149. * an ApplicationContext instance which will be used as the parent context
  150. * of the root WebApplicationContext if it is not null.
  151. * @param servletContext
  152. * @return the parent application context, or null if none
  153. * @throws BeansException if the context couldn't be initialized
  154. */
  155. protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException {
  156. return null;
  157. }
  158. /**
  159. * Close Spring's web application context for the given servlet context.
  160. * @param servletContext current servlet context
  161. */
  162. public void closeWebApplicationContext(ServletContext servletContext) throws ApplicationContextException {
  163. servletContext.log("Closing root WebApplicationContext");
  164. Object wac = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  165. if (wac instanceof ConfigurableApplicationContext) {
  166. ((ConfigurableApplicationContext) wac).close();
  167. }
  168. }
  169. }