View Javadoc

1   // ========================================================================
2   // Copyright (c) 2011 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.servlet.listener;
15  
16  import java.lang.reflect.Field;
17  import java.lang.reflect.InvocationTargetException;
18  import java.lang.reflect.Method;
19  import java.util.Iterator;
20  import java.util.concurrent.ConcurrentHashMap;
21  
22  import javax.servlet.ServletContextEvent;
23  import javax.servlet.ServletContextListener;
24  
25  import org.eclipse.jetty.util.Loader;
26  import org.eclipse.jetty.util.log.Log;
27  
28  /**
29   * ELContextCleaner
30   *
31   * Clean up BeanELResolver when the context is going out
32   * of service:
33   * 
34   * See http://java.net/jira/browse/GLASSFISH-1649
35   * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=353095
36   */
37  public class ELContextCleaner implements ServletContextListener
38  {
39  
40      public void contextInitialized(ServletContextEvent sce)
41      {
42      }
43  
44      public void contextDestroyed(ServletContextEvent sce)
45      {
46          try
47          {
48              //Check that the BeanELResolver class is on the classpath
49              Class beanELResolver = Loader.loadClass(this.getClass(), "javax.el.BeanELResolver");
50  
51              //Get a reference via reflection to the properties field which is holding class references
52              Field field = getField(beanELResolver);
53  
54              //Get rid of references
55              purgeEntries(field);
56              
57              Log.info("javax.el.BeanELResolver purged");
58          }
59          
60          catch (ClassNotFoundException e)
61          {
62              //BeanELResolver not on classpath, ignore
63          }
64          catch (SecurityException e)
65          {
66              Log.warn("Cannot purge classes from javax.el.BeanELResolver", e);
67          }
68          catch (IllegalArgumentException e)
69          {
70              Log.warn("Cannot purge classes from javax.el.BeanELResolver", e);
71          }
72          catch (IllegalAccessException e)
73          {
74              Log.warn("Cannot purge classes from javax.el.BeanELResolver", e);
75          }
76          catch (NoSuchFieldException e)
77          {
78              Log.warn("Cannot purge classes from javax.el.BeanELResolver", e);
79          }
80         
81      }
82  
83  
84      protected Field getField (Class beanELResolver) 
85      throws SecurityException, NoSuchFieldException
86      {
87          if (beanELResolver == null)
88              return  null;
89  
90          return beanELResolver.getDeclaredField("properties");
91      }
92  
93      protected void purgeEntries (Field properties) 
94      throws IllegalArgumentException, IllegalAccessException
95      {
96          if (properties == null)
97              return;
98  
99          if (!properties.isAccessible())
100             properties.setAccessible(true);
101 
102         ConcurrentHashMap map = (ConcurrentHashMap) properties.get(null);
103         if (map == null)
104             return;
105         
106         Iterator<Class> itor = map.keySet().iterator();
107         while (itor.hasNext()) 
108         {
109             Class clazz = itor.next();
110             Log.info("Clazz: "+clazz+" loaded by "+clazz.getClassLoader());
111             if (Thread.currentThread().getContextClassLoader().equals(clazz.getClassLoader()))
112             {
113                 itor.remove();  
114                 Log.info("removed");
115             }
116             else
117                 Log.info("not removed: "+"contextclassloader="+Thread.currentThread().getContextClassLoader()+"clazz's classloader="+clazz.getClassLoader());
118         }
119     }
120 }