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.util.Iterator;
18  import java.util.concurrent.ConcurrentHashMap;
19  
20  import javax.servlet.ServletContextEvent;
21  import javax.servlet.ServletContextListener;
22  
23  import org.eclipse.jetty.util.Loader;
24  import org.eclipse.jetty.util.log.Log;
25  import org.eclipse.jetty.util.log.Logger;
26  
27  /**
28   * ELContextCleaner
29   *
30   * Clean up BeanELResolver when the context is going out
31   * of service:
32   * 
33   * See http://java.net/jira/browse/GLASSFISH-1649
34   * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=353095
35   */
36  public class ELContextCleaner implements ServletContextListener
37  {
38      private static final Logger LOG = Log.getLogger(ELContextCleaner.class);
39  
40  
41      public void contextInitialized(ServletContextEvent sce)
42      {
43      }
44  
45      public void contextDestroyed(ServletContextEvent sce)
46      {
47          try
48          {
49              //Check that the BeanELResolver class is on the classpath
50              Class beanELResolver = Loader.loadClass(this.getClass(), "javax.el.BeanELResolver");
51  
52              //Get a reference via reflection to the properties field which is holding class references
53              Field field = getField(beanELResolver);
54  
55              //Get rid of references
56              purgeEntries(field);
57              
58              LOG.info("javax.el.BeanELResolver purged");
59          }
60          
61          catch (ClassNotFoundException e)
62          {
63              //BeanELResolver not on classpath, ignore
64          }
65          catch (SecurityException e)
66          {
67              LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
68          }
69          catch (IllegalArgumentException e)
70          {
71              LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
72          }
73          catch (IllegalAccessException e)
74          {
75              LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
76          }
77          catch (NoSuchFieldException e)
78          {
79              LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
80          }
81         
82      }
83  
84  
85      protected Field getField (Class beanELResolver) 
86      throws SecurityException, NoSuchFieldException
87      {
88          if (beanELResolver == null)
89              return  null;
90  
91          return beanELResolver.getDeclaredField("properties");
92      }
93  
94      protected void purgeEntries (Field properties) 
95      throws IllegalArgumentException, IllegalAccessException
96      {
97          if (properties == null)
98              return;
99  
100         if (!properties.isAccessible())
101             properties.setAccessible(true);
102 
103         ConcurrentHashMap map = (ConcurrentHashMap) properties.get(null);
104         if (map == null)
105             return;
106         
107         Iterator<Class> itor = map.keySet().iterator();
108         while (itor.hasNext()) 
109         {
110             Class clazz = itor.next();
111             LOG.info("Clazz: "+clazz+" loaded by "+clazz.getClassLoader());
112             if (Thread.currentThread().getContextClassLoader().equals(clazz.getClassLoader()))
113             {
114                 itor.remove();  
115                 LOG.info("removed");
116             }
117             else
118                 LOG.info("not removed: "+"contextclassloader="+Thread.currentThread().getContextClassLoader()+"clazz's classloader="+clazz.getClassLoader());
119         }
120     }
121 }