1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.logging.impl;
19
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22
23 import javax.servlet.ServletContextEvent;
24 import javax.servlet.ServletContextListener;
25
26 import org.apache.commons.logging.LogFactory;
27
28
29 /***
30 * This class is capable of receiving notifications about the undeployment of
31 * a webapp, and responds by ensuring that commons-logging releases all
32 * memory associated with the undeployed webapp.
33 * <p>
34 * In general, the WeakHashtable support added in commons-logging release 1.1
35 * ensures that logging classes do not hold references that prevent an
36 * undeployed webapp's memory from being garbage-collected even when multiple
37 * copies of commons-logging are deployed via multiple classloaders (a
38 * situation that earlier versions had problems with). However there are
39 * some rare cases where the WeakHashtable approach does not work; in these
40 * situations specifying this class as a listener for the web application will
41 * ensure that all references held by commons-logging are fully released.
42 * <p>
43 * To use this class, configure the webapp deployment descriptor to call
44 * this class on webapp undeploy; the contextDestroyed method will tell
45 * every accessable LogFactory class that the entry in its map for the
46 * current webapp's context classloader should be cleared.
47 *
48 * @since 1.1
49 */
50
51 public class ServletContextCleaner implements ServletContextListener {
52
53 private Class[] RELEASE_SIGNATURE = {ClassLoader.class};
54
55 /***
56 * Invoked when a webapp is undeployed, this tells the LogFactory
57 * class to release any logging information related to the current
58 * contextClassloader.
59 */
60 public void contextDestroyed(ServletContextEvent sce) {
61 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
62
63 Object[] params = new Object[1];
64 params[0] = tccl;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 ClassLoader loader = tccl;
97 while (loader != null) {
98
99
100
101 try {
102 Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory");
103 Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE);
104 releaseMethod.invoke(null, params);
105 loader = logFactoryClass.getClassLoader().getParent();
106 } catch(ClassNotFoundException ex) {
107
108
109 loader = null;
110 } catch(NoSuchMethodException ex) {
111
112 System.err.println("LogFactory instance found which does not support release method!");
113 loader = null;
114 } catch(IllegalAccessException ex) {
115
116 System.err.println("LogFactory instance found which is not accessable!");
117 loader = null;
118 } catch(InvocationTargetException ex) {
119
120 System.err.println("LogFactory instance release method failed!");
121 loader = null;
122 }
123 }
124
125
126
127
128 LogFactory.release(tccl);
129 }
130
131 /***
132 * Invoked when a webapp is deployed. Nothing needs to be done here.
133 */
134 public void contextInitialized(ServletContextEvent sce) {
135
136 }
137 }