1 package org.cateproject.controller.context;
2
3 import java.util.Enumeration;
4 import java.util.Map;
5 import java.util.concurrent.ConcurrentHashMap;
6
7 import javax.servlet.ServletContext;
8 import javax.servlet.ServletContextEvent;
9 import javax.servlet.ServletContextListener;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.springframework.beans.BeanUtils;
14 import org.springframework.beans.factory.DisposableBean;
15 import org.springframework.beans.factory.access.BeanFactoryReference;
16 import org.springframework.context.ApplicationContext;
17 import org.springframework.context.ApplicationContextException;
18 import org.springframework.util.ObjectUtils;
19 import org.springframework.web.context.ConfigurableWebApplicationContext;
20 import org.springframework.web.context.ContextLoader;
21 import org.springframework.web.context.WebApplicationContext;
22
23 public class CateContextLoaderListener extends ContextLoader implements ServletContextListener {
24 private static final Log logger = LogFactory.getLog(CateContextLoaderListener.class);
25 private WebApplicationContext context;
26 private static volatile WebApplicationContext currentContext;
27 private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread =
28 new ConcurrentHashMap<ClassLoader, WebApplicationContext>(1);
29 private static final String FAILSAFE_APPLICATION_CONTEXT = "/WEB-INF/classes/org/cateproject/web/applicationContext-failsafe.xml";
30
31 private BeanFactoryReference parentContextRef;
32
33 public void contextInitialized(final ServletContextEvent servletContextEvent) {
34 try {
35 logger.info("Attempting to initialize default context");
36 initWebApplicationContext(servletContextEvent.getServletContext());
37 logger.info("Default context successfully initialized");
38 } catch(Throwable e) {
39 logger.warn("Default Context was not initialized successfully: " + e.getLocalizedMessage());
40
41 if(servletContextEvent.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
42 closeWebApplicationContext(servletContextEvent.getServletContext());
43 logger.info("Partially initialized WebApplicationContext closed");
44 }
45
46 cleanupAttributes(servletContextEvent.getServletContext());
47 logger.info("Loading failsafe context");
48 initFailSafeWebApplicationContext(servletContextEvent.getServletContext());
49 }
50 }
51
52
53
54
55
56
57
58
59
60
61 @Override
62 public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
63 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
64 throw new IllegalStateException(
65 "Cannot initialize context because there is already a root application context present - " +
66 "check whether you have multiple ContextLoader* definitions in your web.xml!");
67 }
68
69 Log logger = LogFactory.getLog(ContextLoader.class);
70 servletContext.log("Initializing Spring root WebApplicationContext");
71 if (logger.isInfoEnabled()) {
72 logger.info("Root WebApplicationContext: initialization started");
73 }
74 long startTime = System.currentTimeMillis();
75
76 try {
77
78 ApplicationContext parent = loadParentContext(servletContext);
79
80
81
82 this.context = createWebApplicationContext(servletContext, parent);
83 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
84
85 ClassLoader ccl = Thread.currentThread().getContextClassLoader();
86 if (ccl == ContextLoader.class.getClassLoader()) {
87 currentContext = this.context;
88 }
89 else if (ccl != null) {
90 currentContextPerThread.put(ccl, this.context);
91 }
92
93 if (logger.isDebugEnabled()) {
94 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
95 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
96 }
97 if (logger.isInfoEnabled()) {
98 long elapsedTime = System.currentTimeMillis() - startTime;
99 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
100 }
101
102 return this.context;
103 }
104 catch (RuntimeException ex) {
105 logger.error("Context initialization failed", ex);
106 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
107 throw ex;
108 }
109 catch (Error err) {
110 logger.error("Context initialization failed", err);
111 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
112 throw err;
113 }
114 }
115
116
117 private WebApplicationContext initFailSafeWebApplicationContext(ServletContext servletContext) {
118 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
119 throw new IllegalStateException(
120 "Cannot initialize context because there is already a root application context present - " +
121 "check whether you have multiple ContextLoader* definitions in your web.xml!");
122 }
123
124 Log logger = LogFactory.getLog(ContextLoader.class);
125 servletContext.log("Initializing Spring root WebApplicationContext");
126 if (logger.isInfoEnabled()) {
127 logger.info("Root WebApplicationContext: initialization started");
128 }
129 long startTime = System.currentTimeMillis();
130
131 try {
132
133 ApplicationContext parent = loadParentContext(servletContext);
134
135
136
137
138 this.context = createFailSafeWebApplicationContext(servletContext, parent);
139 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
140
141 ClassLoader ccl = Thread.currentThread().getContextClassLoader();
142 if (ccl == ContextLoader.class.getClassLoader()) {
143 currentContext = this.context;
144 }
145 else if (ccl != null) {
146 currentContextPerThread.put(ccl, this.context);
147 }
148
149 if (logger.isDebugEnabled()) {
150 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
151 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
152 }
153 if (logger.isInfoEnabled()) {
154 long elapsedTime = System.currentTimeMillis() - startTime;
155 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
156 }
157
158 return this.context;
159 }
160 catch (RuntimeException ex) {
161 logger.error("Context initialization failed", ex);
162 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
163 throw ex;
164 }
165 catch (Error err) {
166 logger.error("Context initialization failed", err);
167 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
168 throw err;
169 }
170
171 }
172
173 protected WebApplicationContext createFailSafeWebApplicationContext(ServletContext sc, ApplicationContext parent) {
174 Class<?> contextClass = determineContextClass(sc);
175 if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
176 throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
177 "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
178 }
179 ConfigurableWebApplicationContext wac =
180 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
181
182
183 if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
184
185 String servletContextName = sc.getServletContextName();
186 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
187 ObjectUtils.getDisplayString(servletContextName));
188 }
189 else {
190
191 try {
192 String contextPath = (String) ServletContext.class.getMethod("getContextPath").invoke(sc);
193 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
194 ObjectUtils.getDisplayString(contextPath));
195 }
196 catch (Exception ex) {
197 throw new IllegalStateException("Failed to invoke Servlet 2.5 getContextPath method", ex);
198 }
199 }
200
201 wac.setParent(parent);
202 wac.setServletContext(sc);
203
204 wac.setConfigLocation(FAILSAFE_APPLICATION_CONTEXT);
205 customizeContext(sc, wac);
206 wac.refresh();
207 return wac;
208 }
209
210 @Override
211 protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) {
212 Class<?> contextClass = determineContextClass(sc);
213 if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
214 throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
215 "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
216 }
217 ConfigurableWebApplicationContext wac =
218 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
219
220
221 if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
222
223 String servletContextName = sc.getServletContextName();
224 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
225 ObjectUtils.getDisplayString(servletContextName));
226 }
227 else {
228
229 try {
230 String contextPath = (String) ServletContext.class.getMethod("getContextPath").invoke(sc);
231 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
232 ObjectUtils.getDisplayString(contextPath));
233 }
234 catch (Exception ex) {
235 throw new IllegalStateException("Failed to invoke Servlet 2.5 getContextPath method", ex);
236 }
237 }
238
239 wac.setParent(parent);
240 wac.setServletContext(sc);
241 wac.setConfigLocation(sc.getInitParameter(CONFIG_LOCATION_PARAM));
242 customizeContext(sc, wac);
243 wac.refresh();
244 return wac;
245 }
246
247
248
249
250
251
252
253
254
255
256 @Override
257 public void closeWebApplicationContext(ServletContext servletContext) {
258 servletContext.log("Closing Spring root WebApplicationContext");
259 try {
260 if (this.context instanceof ConfigurableWebApplicationContext) {
261 ((ConfigurableWebApplicationContext) this.context).close();
262 }
263 }
264 finally {
265 ClassLoader ccl = Thread.currentThread().getContextClassLoader();
266 if (ccl == ContextLoader.class.getClassLoader()) {
267 currentContext = null;
268 }
269 else if (ccl != null) {
270 currentContextPerThread.remove(ccl);
271 }
272 servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
273 if (this.parentContextRef != null) {
274 this.parentContextRef.release();
275 }
276 }
277 }
278
279
280
281 private void cleanupAttributes(ServletContext servletContext) {
282 Enumeration attrNames = servletContext.getAttributeNames();
283 while (attrNames.hasMoreElements()) {
284 String attrName = (String) attrNames.nextElement();
285 if (attrName.startsWith("org.springframework.")) {
286 Object attrValue = servletContext.getAttribute(attrName);
287 if (attrValue instanceof DisposableBean) {
288 try {
289 ((DisposableBean) attrValue).destroy();
290 } catch (Throwable ex) {
291 logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex);
292 }
293 }
294 }
295 }
296 }
297
298 public void contextDestroyed(ServletContextEvent servletContextEvent) {
299 closeWebApplicationContext(servletContextEvent.getServletContext());
300 cleanupAttributes(servletContextEvent.getServletContext());
301 }
302
303 }