Fixing glassfish 4.1.1 memory leak (again)

It's again annoying to restart the glassfish instance again and again because it's out of memory.
In the current version glassfish 4.1.1 I am using the same technique to free the leaked memory as before. (Read here glassfish-memory-leak.wiki).
Instead of reporting further bugs, Iam publishing the code of my ContextListener. It's not a pretty code but a working one.
package de.bb.glassfish.memory.leak;

import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.WeakHashMap;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import de.bb.util.LRUCache;

public class ContextListener implements ServletContextListener {

    private final static Logger LOG = Logger.getLogger(ContextListener.class);


    public void contextDestroyed(ServletContextEvent sce) {
        // LOG.setLevel(Level.DEBUG);
        fixAppserver();
        LOG.info("flushing bean caches");
        Introspector.flushCaches();
        LOG.info("clearing ResourceBundle cache");
        ResourceBundle.clearCache();
        LOG.info("closing LOG");
        LogManager.shutdown();
        LOG.info("stopping LRUCache");
        LRUCache.shutDown();

        // NOTE: YOU CAN'T INVOKE EJBs HERE - APP IS SHUTDOWN!!!
    }

    public void contextInitialized(final ServletContextEvent sce) {
    }

    private void fixAppserver() {
        final Thread threads[] = getThreads();
        final HashSet<ClassLoader> gfClassLoaders = isGlassfish(threads);
        if (!gfClassLoaders.isEmpty()) {
            fixGlassfish(threads, gfClassLoaders);
        }
    }

    /**
     * Get all threads. (really? There are threads not inside thread groups!!!)
     * 
     * @return an array with all threads.
     */
    private Thread[] getThreads() {
        for (int size = 200;; size += size) {
            final Thread[] threads = new Thread[size];
            // start searching from the topmost thread group to search all threads
            ThreadGroup root = Thread.currentThread().getThreadGroup();
            while (root.getParent() != null) {
                root = root.getParent();
            }
            int n = root.enumerate(threads);
            if (n < size) {
                final Thread[] result = new Thread[n];
                System.arraycopy(threads, 0, result, 0, n);
                return result;
            }
        }
    }

    /**
     * Fill a collection with the typical glassfish class loaders.
     * 
     * @param threads
     *            all found threads.
     * @return
     */
    private HashSet<ClassLoader> isGlassfish(final Thread[] threads) {
        final HashSet<ClassLoader> result = new HashSet<ClassLoader>();
        for (final Thread thread : threads) {
            if (thread == null)
                break;
            for (ClassLoader cl = thread.getClass().getClassLoader(); cl != null; cl = cl.getParent()) {
                final String clName = cl.getClass().getName();
                if (clName.endsWith("ClassLoaderJava5")) {
                    result.add(cl);
                }
            }
        }
        return result;
    }

    /**
     * Apply cleanup fixes for the broken glassfish server.
     * 
     * @param threads
     * @param gfClassLoaders
     */
    private void fixGlassfish(final Thread[] threads, final HashSet<ClassLoader> gfClassLoaders) {
        try {
            // remove only my class loader
            LOG.info("fixing glassfish");

            // determine class loader urls to identify my own classloader
            final Set<Object> myUrlSet = new HashSet<Object>();
            ClassLoader myClassLoader = this.getClass().getClassLoader();
            for (ClassLoader cl = myClassLoader; cl != null; cl = cl.getParent()) {
                if (cl.getClass().getName().indexOf("Ear") >= 0) {
                    myClassLoader = cl;

                    final Set<Object> set = (Set<Object>) getMember(myClassLoader, "urlSet");
                    myUrlSet.addAll(set);
                }
            }

            fixWebBundleClassloader(myUrlSet, myClassLoader);

            fixJavaBug7199818(myUrlSet, myClassLoader);

            fixGlassfishBugWSIT1655(myUrlSet, myClassLoader);

            fixGlassfishBug17468(myUrlSet, myClassLoader);

            fixGlassfishBugxxxx(myUrlSet, myClassLoader);

            fixResourceManager();

            for (Thread thread : threads) {
                if (thread == null)
                    break;
                try {
                    cleanThread(thread, myClassLoader, myUrlSet);
                } catch (Exception ex) {
                    LOG.error(ex, ex);
                }
            }

            fixORB();

            fixClassCopier(myUrlSet, myClassLoader);

            fixWebserviceEndpoints(myUrlSet, myClassLoader);

            fixInjector();

            fixObjectCopierImpl(myUrlSet, myClassLoader);

            fixClassInfoCache(myUrlSet, myClassLoader);

            fixRepositoryClassToRep(gfClassLoaders, myUrlSet, myClassLoader);

            fixJavaFaces(myUrlSet, myClassLoader);

        } catch (Exception ex2) {
            LOG.error(ex2, ex2);
        }
    }

    /**
     * This fix causes an exception during application shutdown, but without there is a memory leak
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixJavaFaces(Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            final Class<?> factoryFinder = Class.forName("javax.faces.FactoryFinder");
            if (factoryFinder == null)
                return;

            final Object currentThreadToServletContext = getMember(null, factoryFinder, "FACTORIES_CACHE");
            if (currentThreadToServletContext == null)
                return;

            final Map applicationMap = (Map) getMember(currentThreadToServletContext, "applicationMap");
            if (applicationMap == null)
                return;

            for (Iterator<Entry> i = applicationMap.entrySet().iterator(); i.hasNext();) {
                final Entry e = i.next();
                final Object o = getMember(e.getKey(), "cl");
                if (o instanceof ClassLoader) {
                    ClassLoader cl = (ClassLoader) o;
                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                        LOG.info("fix JavaFaces factory cache - remove: " + e.getValue());
                        i.remove();
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }

        try {
            final Class factoryContext = Class.forName("javax.faces.context.FacesContext");
            if (factoryContext == null)
                return;

            final Map initContextServletContext = (Map) getMember(null, factoryContext, "initContextServletContext");

            if (initContextServletContext == null)
                return;

            for (Iterator<Entry> i = initContextServletContext.entrySet().iterator(); i.hasNext();) {
                final Entry e = i.next();
                final Object o = getMember(e.getValue(), "context.context.wmInfo._appClassLoader");
                if (o instanceof ClassLoader) {
                    final ClassLoader cl = (ClassLoader) o;
                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                        LOG.info("fix JavaFaces initContextServletContext - remove: " + e.getValue());
                        i.remove();
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }

    }

    private void fixRepositoryClassToRep(final HashSet<ClassLoader> gfClassLoaders, final Set<Object> myUrlSet,
            ClassLoader myClassLoader) {
        try {
            for (final ClassLoader cl : gfClassLoaders) {
                final Collection<Class<?>> classes = (Collection<Class<?>>) getMember(cl, "classes");
                for (Class<?> c : classes) {
                    if (c.getName().equals("com.sun.corba.ee.impl.util.RepositoryId")) {
                        LOG.info("clearing com.sun.corba.ee.impl.util.RepositoryId:classToRepStr");
                        final Map<?, ?> classToRepStr = (Map<?, ?>) getMember(null, c, "classToRepStr");
                        classToRepStr.clear();

                        final Map<?, ?> repStrToClass = (Map<?, ?>) getMember(null, c, "repStrToClass");
                        repStrToClass.toString();
                        for (Iterator<?> i = repStrToClass.values().iterator(); i.hasNext();) {
                            Class<?> aClass = (Class<?>) i.next();
                            if (aClass != null && refersToMyEar(aClass.getClassLoader(), myClassLoader, myUrlSet)) {
                                LOG.info("remove repStrToClass for: " + aClass);
                                i.remove();
                            }
                        }

                    } else if (c.getName().equals("com.sun.corba.ee.impl.copyobject.ReflectObjectCopierImpl")) {
                        final Object ccf = getMember(null, c, "ccf");
                        clearCcf(myUrlSet, myClassLoader, ccf);

                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * Clean the ClassInfoCache for items refering to our class loader.
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixClassInfoCache(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            // class com.sun.corba.ee.impl.orbutil.ClassInfoCache
            final Map<?, ?> classData = (Map<?, ?>) getMember(null,
                    Class.forName("com.sun.corba.ee.impl.orbutil.ClassInfoCache"), "classData");
            for (Iterator<?> i = classData.keySet().iterator(); i.hasNext();) {
                Class<?> aClass = (Class<?>) i.next();
                if (aClass != null && refersToMyEar(aClass.getClassLoader(), myClassLoader, myUrlSet)) {
                    LOG.info("remove ClassInfoCache for: " + aClass);
                    i.remove();
                }
            }
            // ???
            classData.clear();
        } catch (ClassNotFoundException cfne) {
            // nada
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * Clear references to our class loader from ObjectCopierImpl.
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixObjectCopierImpl(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            Class<?> clazz = null;
            try {
                clazz = Class.forName("com.sun.corba.ee.impl.orbutil.copyobject.ObjectCopierImpl");
            } catch (Exception ex) {
                // gf4
                clazz = Class.forName("org.glassfish.pfl.dynamic.copyobject.impl.ObjectCopierImpl");
            }
            // clean class ObjectCopierImpl
            final Object ccf = getMember(null, clazz, "ccf");
            clearCcf(myUrlSet, myClassLoader, ccf);

        } catch (ClassNotFoundException cnfe) {
            // nada
        } catch (Throwable ex) {
        }
    }

    /**
     * Clear all injectors.
     */
    private void fixInjector() {
        try {
            // clean class com.sun.xml.bind.v2.runtime.reflect.opt.Injector
            final Map<?, ?> injectors = (Map<?, ?>) getMember(null,
                    Class.forName("com.sun.xml.bind.v2.runtime.reflect.opt.Injector"), "injectors");
            injectors.clear();
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * Fix web bundle class loaders.
     */
    private void fixWebBundleClassloader(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            // clean web bundle class loaders
            final Object initctx_factory_builder =
                    getMember(null, Class.forName("javax.naming.spi.NamingManager"), "initctx_factory_builder");
            final Map<?, ?> table = (Map<?, ?>) getMember(initctx_factory_builder, "sc.habitat.byType.store");
            if (table != null) {
                for (final Object oal : table.values()) {
                    final ArrayList<?> al = (ArrayList<?>) oal;
                    for (final Object o : al) {
                        if (!o.getClass().getName().equals("com.sun.hk2.component.LazyInhabitant"))
                            continue;
                        final Object real = getMember(o, "real");
                        if (real == null
                                || !real.getClass().getName().equals("com.sun.hk2.component.SingletonInhabitant"))
                            continue;
                        final Object object = getMember(real, "object");
                        if (object.getClass().getName()
                                .equals("com.sun.enterprise.security.webservices.GFServerPipeCreator")) {
                            final Object webBundleDescriptor =
                                    getMember(object, "endpoint.webComponentImpl.webBundleDescriptor");
                            final ClassLoader cl = (ClassLoader) getMember(webBundleDescriptor, "classLoader");
                            if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                LOG.info("releasing LazyInhabitant to my application");
                                setMember(o, "real", null);
                            }
                        } else if (object.getClass().getName().endsWith(".ApplicationRegistry")) {
                            final Map<?, ?> apps = (Map<?, ?>) getMember(object, "apps");
                            for (final Object cai : apps.values()) {
                                ClassLoader cl0 = (ClassLoader) getMember(cai, "appClassLoader");
                                final ArrayList<?> modules = (ArrayList<?>) getMember(cai, "modules");
                                for (final Object moduleInfo : modules) {
                                    ClassLoader cl = (ClassLoader) getMember(moduleInfo, "moduleClassLoader");
                                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                        final HashSet<?> engines = (HashSet<?>) getMember(moduleInfo, "engines");
                                        for (final Object engineRef : engines) {
                                            try {
                                                final Object cl2 = getMember(engineRef, "appCtr.ejbAppClassLoader");
                                                cl2.toString();
                                            } catch (Exception ex3) {
                                                LOG.error(ex3, ex3);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            // new bug in gf4 / gf4.1
            final Set<?> sortedList =
                    (Set<?>) getMember(initctx_factory_builder, "sc.services.allDescriptors.sortedList");
            if (sortedList != null) {
                Outer: for (Iterator<Object> i = (Iterator<Object>) sortedList.iterator(); i.hasNext();) {
                    final Object v = i.next();
                    final Object o = getMember(v, "cachedValue");
                    if (o != null) {
                        if (o.getClass().getName()
                                .equals("com.sun.enterprise.security.webservices.GFServerPipeCreator")) {

                            final ClassLoader cl = (ClassLoader) getMember(o,
                                    "endpoint.webComponentImpl.webBundleDescriptor.classLoader");
                            if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                LOG.info("removing webservice GFServerPipeCreator: " + o);
                                i.remove();
                                continue Outer;
                            }

                            final Set<?> s2 = (Set<?>) getMember(o,
                                    "endpoint.webComponentImpl.webBundleDescriptor.ejbReferences");
                            for (final Object o2 : s2) {
                                final Map<?, ?> m3 = (Map<?, ?>) getMember(o2,
                                        "ejbDescriptor.bundleDescriptor.entityManagerFactories");
                                for (final Object o3 : m3.values()) {
                                    final Map<?, ?> m4 = (Map<?, ?>) getMember(o3, "delegate.session.descriptors");
                                    for (final Object o4 : m4.values()) {
                                        final Object o5 = getMember(o4, "instantiationPolicy.factory");
                                        if (refersToMyEar(o5.getClass().getClassLoader(), myClassLoader, myUrlSet)) {
                                            i.remove();
                                            continue Outer;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * Release end points.
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixWebserviceEndpoints(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            // fix the WebService endpoints
            final Map<?, ?> modules = (Map<?, ?>) getMember(null,
                    Class.forName("org.glassfish.webservices.JAXWSServletModule"), "modules");

            for (Iterator<?> i = modules.entrySet().iterator(); i.hasNext();) {
                final Entry<?, ?> e = (Entry<?, ?>) i.next();
                final Map<?, ?> endpoints = (Map<?, ?>) getMember(e.getValue(), "endpoints");
                boolean remove = false;
                if (endpoints != null)
                    for (Object endpoint : endpoints.values()) {
                        try {
                            Map<?, ?> beanInfoMap =
                                    (Map<?, ?>) getMember(endpoint, "endpoint.seiModel.jaxbContext.beanInfoMap");

                            // gf4
                            if (beanInfoMap == null)
                                beanInfoMap = (Map<?, ?>) getMember(endpoint,
                                        "serviceDefinition.owner.seiModel.bindingContext.context.beanInfoMap");

                            if (beanInfoMap != null)
                                for (final Object value : beanInfoMap.values()) {
                                    final String vclassName = value.getClass().getName();
                                    if (!vclassName.contains("ClassBeanInfoImpl"))
                                        continue;

                                    final Object[] properties = (Object[]) getMember(value, "properties");
                                    for (final Object prop : properties) {
                                        final String pclassName = prop.getClass().getName();
                                        if (!pclassName.contains("SingleElementLeafProperty"))
                                            continue;

                                        final Object xacc = getMember(prop, "xacc");
                                        final Object acc = getMember(xacc, "acc");

                                        final ClassLoader cl = acc.getClass().getClassLoader();
                                        if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                            remove = true;
                                            break;
                                        }
                                        if (remove)
                                            break;
                                    }
                                    if (remove)
                                        break;
                                }
                        } catch (Exception exxx) {
                            LOG.error(exxx, exxx);
                        }
                        if (remove)
                            break;
                    }
                if (remove) {
                    LOG.info("removing webservice endpoints: " + endpoints);
                    i.remove();
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * fix class copier.
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixClassCopier(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            Class<?> clazz = null;
            try {
                clazz = Class.forName("com.sun.corba.ee.impl.orbutil.copyobject.ClassCopierOrdinaryImpl");
            } catch (Exception ex) {
                // gf4
                clazz = Class.forName("org.glassfish.pfl.dynamic.copyobject.impl.ClassCopierOrdinaryImpl");
            }
            // clean class ClassCopierOrdinaryImpl
            final Map<?, ?> classToClassFieldCopier = (Map<?, ?>) getMember(null, clazz, "classToClassFieldCopier");
            for (Iterator<?> i = classToClassFieldCopier.values().iterator(); i.hasNext();) {
                Object val = i.next();
                Class<?> myClass = (Class<?>) getMember(val, "myClass");
                if (myClass != null && refersToMyEar(myClass.getClassLoader(), myClassLoader, myUrlSet)) {
                    LOG.info("remove classToClassFieldCopier for: " + myClass);
                    i.remove();
                }
            }
        } catch (ClassNotFoundException cfne) {
            // nada
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    private void fixORB() {
        try {
            // fix the ORB
            final Object globalPM = getMember(null, Class.forName("com.sun.corba.ee.spi.orb.ORB"), "globalPM");
            final Object weakCache = getMember(globalPM, "classToClassData");
            final Map<?, ?> classToClassData = (Map<?, ?>) getMember(weakCache, "map");

            LOG.info("clearing classToclassData map");
            classToClassData.clear();

        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    private void fixResourceManager() {
        try {
            final Class<?> resourceManager = Class.forName("com.sun.naming.internal.ResourceManager");
            Map<?, ?> propertiesCache = (Map<?, ?>) getMember(null, resourceManager, "propertiesCache");
            propertiesCache.clear();
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    private void fixGlassfishBugxxxx(Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            final Class<?> clazz = Class.forName("org.hibernate.validator.internal.util.ReflectionHelper");
            final Object typeResolver = getMember(null, clazz, "typeResolver");
            final Map<?, ?> map = (Map<?, ?>) getMember(typeResolver, "_resolvedTypes._map");
            if (map != null)
                map.clear();
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * see http://java.net/jira/browse/GLASSFISH-17468
     * 
     * fixed in 3.1.2
     * 
     * @param myClassLoader
     * @param myUrlSet
     */
    private void fixGlassfishBug17468(Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            // find the context config and flush the error handler.
            final Object digester =
                    getMember(null, Class.forName("org.apache.catalina.startup.ContextConfig"), "contextDigester");

            if (digester != null) {
                LOG.info("nulling errorHandler ");
                setMember(digester, "errorHandler", null);

                final ClassLoader cl = (ClassLoader) getMember(digester, "classLoader");
                if (cl != null) {
                    if (refersToMyEar(cl, myClassLoader, myUrlSet)
                            || refersToMyEar(cl.getParent(), myClassLoader, myUrlSet)) {
                        setMember(digester, "classLoader", null);
                    }
                }
            }

        } catch (Exception ex) {
            LOG.error(ex);
        }
    }

    /**
     * see http://java.net/jira/browse/WSIT-1655
     * 
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixGlassfishBugWSIT1655(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            // clean BaseAuthConfigFactory
            final Map<?, ?> provider2IdsMap = (Map<?, ?>) getMember(null,
                    Class.forName("com.sun.jaspic.config.factory.BaseAuthConfigFactory"), "provider2IdsMap");
            for (final Object acp : provider2IdsMap.keySet()) {
                try {
                    final Map<?, ?> serverConfigMap = (Map<?, ?>) getMember(acp, "serverConfigMap");
                    if (serverConfigMap != null)
                        for (Iterator<?> i = serverConfigMap.entrySet().iterator(); i.hasNext();) {
                            final Entry<?, ?> e = (Entry<?, ?>) i.next();
                            try {
                                final ClassLoader cl = (ClassLoader) getMember(e.getValue(),
                                        "callbackHandler.handler.handlerContext.this$0.seiModel.classLoader");
                                if (cl != null && refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                    i.remove();
                                    continue;
                                }
                            } catch (Exception ex2) {
                                LOG.error(ex2, ex2);
                            }
                            try {
                                final Class<?>[] classes = (Class<?>[]) getMember(e.getValue(),
                                        "callbackHandler.handler.handlerContext.this$0.seiModel.jaxbContext.classes");
                                if (classes != null)
                                    for (Class<?> c : classes) {
                                        if (refersToMyEar(c.getClassLoader(), myClassLoader, myUrlSet)) {
                                            i.remove();
                                            break;
                                        }
                                    }
                            } catch (Exception ex2) {
                                LOG.error(ex2, ex2);
                            }
                        }
                } catch (Exception ex) {
                    LOG.error(ex, ex);
                }
            }
        } catch (Throwable ex) {
            LOG.error(ex, ex);
        }
    }

    /**
     * see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7199818.
     * 
     * @param myUrlSet
     * @param myClassLoader
     */
    private void fixJavaBug7199818(final Set<Object> myUrlSet, ClassLoader myClassLoader) {
        try {
            final Class<?> configuration = Class.forName("javax.security.auth.login.Configuration");
            ClassLoader cl = (ClassLoader) getMember(null, configuration, "contextClassLoader");
            if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                do {
                    cl = cl.getParent();
                } while (refersToMyEar(cl, myClassLoader, myUrlSet));
                setMember(null, configuration, "contextClassLoader", cl);
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    private void clearCcf(final Set<Object> myUrlSet, ClassLoader myClassLoader, final Object ccf)
            throws NoSuchFieldException, IllegalAccessException {
        LOG.info("clear ccf");
        final Map<?, ?> cache = (Map<?, ?>) getMember(ccf, "factoryCache.cache");
        for (Iterator<?> i = cache.values().iterator(); i.hasNext();) {
            final Object cfc = i.next();
            try {
                Class<?> myClass = (Class<?>) getMember(cfc, "classFieldCopier.myClass");
                if (myClass != null && refersToMyEar(myClass.getClassLoader(), myClassLoader, myUrlSet)) {
                    LOG.info("removing ClassCopier for: " + myClass.getName());
                    i.remove();
                    continue;
                }
                myClass = (Class<?>) getMember(cfc, "constructor.clazz");
                if (myClass != null && refersToMyEar(myClass.getClassLoader(), myClassLoader, myUrlSet)) {
                    LOG.info("removing ClassCopier for: " + myClass.getName());
                    i.remove();
                }
            } catch (Exception ex2) {
                LOG.error(ex2, ex2);
            }
        }
    }

    /**
     * Helper function to set a member of the given object.
     * 
     * @param reference
     *            the object to search for member
     * @param memberName
     *            the name of the member
     * @param value
     *            the value to set
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void setMember(final Object reference, String memberName, Object value)
            throws NoSuchFieldException, IllegalAccessException {
        setMember(reference, reference.getClass(), memberName, value);
    }

    private void setMember(Object reference, Class<? extends Object> clazz, String memberName, Object value)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        try {
            final Field field = clazz.getDeclaredField(memberName);
            field.setAccessible(true);
            field.set(reference, value);
        } catch (NoSuchFieldException nsfe) {
            if (clazz.getSuperclass() == null)
                throw nsfe;
            setMember(reference, clazz.getSuperclass(), memberName, value);
        }

    }

    /**
     * Helper function to get a member of the given object.
     * 
     * @param reference
     *            the object to search for member
     * @param memberName
     *            the name of the member
     * @return the object
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static Object getMember(Object reference, String memberName) {
        try {
            for (StringTokenizer st = new StringTokenizer(memberName, "."); st.hasMoreTokens();) {
                reference = getMember(reference, reference.getClass(), st.nextToken());
            }
            return reference;
        } catch (Exception ex) {
        }
        return null;
    }

    private static Object getMember(Object reference, Class<?> clazz, String memberName)
            throws NoSuchFieldException, IllegalAccessException {
        try {
            // if (reference instanceof WeakReference<?>) {
            // reference = ((WeakReference<?>) reference).get();
            // if (memberName.equals("value"))
            // return reference;
            // clazz = reference.getClass();
            // }
            final Field memberField = clazz.getDeclaredField(memberName);
            memberField.setAccessible(true);
            final Object object = memberField.get(reference);
            return object;
        } catch (NoSuchFieldException nsfe) {
            if (clazz.getSuperclass() == null)
                return null;
            return getMember(reference, clazz.getSuperclass(), memberName);
        }
    }

    private void cleanThread(final Thread thread, ClassLoader myClassLoader, Set<Object> myUrlSet)
            throws NoSuchFieldException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {

        LOG.debug("checking thread: " + thread.getName() + " - " + thread.getClass()
                + (thread.getContextClassLoader() != null ? " with " + thread.getContextClassLoader().getClass() : ""));

        // context class loader
        if (refersToMyEar(thread.getContextClassLoader(), myClassLoader, myUrlSet)) {
            final Object target = getMember(thread, "target");
            if (target != null) {
                LOG.info("removing the context class loader from thread: " + thread.getName() + " - "
                        + target.getClass());
            } else {
                LOG.info("removing the context class loader from thread: " + thread.getClass());
            }

            ClassLoader cl = thread.getContextClassLoader();
            do {
                cl = cl.getParent();
            } while (refersToMyEar(cl, myClassLoader, myUrlSet));
            thread.setContextClassLoader(cl);

            if (thread.getContextClassLoader() != cl)
                setMember(thread, "contextClassLoader", cl);
        }

        try {
            final Object selector = getMember(thread, "currentWork.orb.transportManager.selector");
            if (selector != null) {
                final ClassLoader cl = (ClassLoader) getMember(selector, "contextClassLoader");
                if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                    setMember(selector, "contextClassLoader", null);
                }
            }
        } catch (Exception ex) {
        }

        // try to access the orb
        try {
            final Map<?, ?> objectNameMap = (Map<?, ?>) getMember(thread, "currentWork.orb.mom.tree.objectNameMap");
            if (objectNameMap != null) {
                for (final Object entry : objectNameMap.values()) {
                    if (entry == null || !entry.getClass().getName().endsWith(".POAImpl"))
                        continue;
                    final Object mediator = getMember(entry, "mediator");
                    if (mediator == null)
                        continue;

                    if (mediator.getClass().getName().endsWith("_R_AOM")) {
                        final Map<?, ?> servantToEntry =
                                (Map<?, ?>) getMember(mediator, "activeObjectMap.servantToEntry");
                        for (final Object key : servantToEntry.keySet()) {
                            if (key == null || !key.getClass().getName().endsWith("TransientNamingContext"))
                                continue;
                            final Map<?, ?> table = (Map<?, ?>) getMember(key, "bindingMap");
                            for (final Object or : table.values()) {
                                final Object theObjectRef = getMember(or, "theObjectRef");
                                final ClassLoader cl2 = theObjectRef.getClass().getClassLoader();
                                if (refersToMyEar(cl2, myClassLoader, myUrlSet)) {
                                    table.clear();
                                    break;
                                }
                            }
                        }
                        continue;
                    }

                    if (mediator.getClass().getName().endsWith("_NR_USM")) {
                        final Object locator = getMember(mediator, "locator");
                        if (locator != null) {
                            ClassLoader cl2 = (ClassLoader) getMember(locator, "appClassLoader");
                            if (refersToMyEar(cl2, myClassLoader, myUrlSet)) {
                                setMember(locator, "appClassLoader", null);
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
        }

        try {
            Map<?, ?> map = (Map<?, ?>) getMember(thread, "currentWork.orb.objectKeyCache.map");
            if (map != null) {
                LOG.info("clearing orb.objectKeyCache.map");
                map.clear();
            }
        } catch (Exception ex) {
            // LOG.error(ex);
        }

        // thread locals
        final Object threadLocals = getMember(thread, "threadLocals");
        if (threadLocals != null) {
            final Object[] table = (Object[]) getMember(threadLocals, "table");
            for (int i = 0; i < table.length; ++i) {
                Object entry = table[i];
                if (entry == null)
                    continue;

                final Object value = getMember(entry, "value");
                if (value != null) {
                    final String vcName = value.getClass().getName();
                    if (vcName.equals("com.sun.enterprise.security.authorize.HandlerData")) {
                        LOG.info("TLS nulling handler data for: " + thread);
                        setMember(entry, "value", null);
                    } else if (value instanceof ClassLoader
                            && refersToMyEar((ClassLoader) value, myClassLoader, myUrlSet)) {
                        LOG.info("TLS removing the class loader from thread: " + thread);
                        setMember(entry, "value", myClassLoader.getParent());
                    } else if (vcName.equals("com.sun.corba.ee.impl.orb.ORBImpl")) {
                        final Object transportManager = getMember(value, "transportManager");
                        if (transportManager == null)
                            continue;
                        final Object selector = getMember(transportManager, "selector");
                        if (selector == null)
                            continue;
                        final ClassLoader contextClassLoader = (ClassLoader) getMember(selector, "contextClassLoader");
                        if (contextClassLoader == null)
                            continue;

                        if (refersToMyEar(contextClassLoader, myClassLoader, myUrlSet)) {
                            LOG.info("removing the class loader from ORB impl: " + value);
                            setMember(selector, "contextClassLoader", myClassLoader.getParent());

                            final Object objectKeyCache = getMember(value, "objectKeyCache");
                            final Map<?, ?> map = (Map<?, ?>) getMember(objectKeyCache, "map");
                            LOG.info("clearing object key cache");
                            map.clear();
                        }
                    } else if (vcName.equals("com.sun.corba.ee.impl.oa.poa.POAImpl$1")) {
                        final ClassLoader appClassLoader =
                                (ClassLoader) getMember(value, "this$0.mediator.locator.appClassLoader");
                        if (refersToMyEar(appClassLoader, myClassLoader, myUrlSet)) {
                            table[i] = null;
                        }
                    } else if (vcName.equals("com.sun.corba.ee.spi.orbutil.codegen.Wrapper$Environment")
                            || vcName.equals("org.glassfish.pfl.dynamic.codegen.spi.Wrapper$Environment")) {
                        LOG.info("clearing Wrapper$Environment");
                        setMember(value, "root", null);
                        table[i] = null;
                    } else if (value instanceof WeakHashMap<?, ?>) {
                        LOG.info("emptying a WeakHashMap");
                        WeakHashMap<?, ?> wh = (WeakHashMap<?, ?>) value;
                        wh.clear();
                    } else if (vcName.equals("com.sun.jts.jta.TransactionManagerImpl")) {
                        try {
                            final ClassLoader vcl = value.getClass().getClassLoader();
                            Vector<Class<?>> clazzez = (Vector<Class<?>>) getMember(vcl, "classes");
                            Class<?> rtClazz = null;
                            for (final Class<?> c : clazzez) {
                                if (c.getName().equals("com.sun.jts.CosTransactions.RecoveryManager")) {
                                    rtClazz = c;
                                    break;
                                }
                            }
                            final Thread resyncThread = (Thread) getMember(null, rtClazz, "resyncThread");
                            if (resyncThread != null) {
                                cleanThread(resyncThread, myClassLoader, myUrlSet);
                            }
                        } catch (Exception ex) {
                        }
                    }
                }
            }
        }

        // // fix targets = Runnables
        // final Object target = getMember(thread, "target");
        // if (target != null) {
        // final String tcName = target.getClass().getName();
        // if (tcName.equals("org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor")) {
        // final Object webModule = getMember(target, "this$0");
        // webModule.toString();
        // }
        // }

        try {
            final Object[] context = (Object[]) getMember(thread, "inheritedAccessControlContext.context");
            if (context != null) {
                for (final Object o : context) {
                    ClassLoader cl = (ClassLoader) getMember(o, "classLoader");
                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                        LOG.info("removing the class loader from inheritedAccessControlContext.context[..].context");
                        setMember(o, "classLoader", null);
                    }
                    cl = (ClassLoader) getMember(o, "classloader");
                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                        LOG.info("removing the class loader from inheritedAccessControlContext.context[..].context");
                        setMember(o, "classloader", null);
                    }
                }
            }
        } catch (Exception ex) {
            // LOG.error(ex, ex);
        }

        // new in 4.0.1
        try {
            final Object threadPool = getMember(thread, "orb.threadpoolMgr.threadPool");
            if (threadPool != null) {
                final ClassLoader cl = (ClassLoader) getMember(threadPool, "workerThreadClassLoader");
                if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                    LOG.info("nulling orb.threadPoolMgr.threadPool.workerThread");
                    setMember(threadPool, "workerThreadClassLoader", null);
                }
            }
        } catch (Exception ex) {
        }

        // new in 4.1.1 ? maybe earlier
        try {
            final Collection list = (Collection) getMember(thread, "this$0.habitat.allDescriptors.unsortedList");
            if (list != null) {
                for (final Iterator i = list.iterator(); i.hasNext();) {
                    final Object o = i.next();
                    if (o == null)
                        continue;
                    if (o.getClass().getName().equals("org.jvnet.hk2.internal.SystemDescriptor")) {
                        ClassLoader cl = (ClassLoader) getMember(o,
                                "cachedValue.endpoint.webComponentImpl.webBundleDescriptor.classLoader");
                        if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                            LOG.info("removing from allDescriptors: " + o);
                            i.remove();
                            continue;
                        }
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }

        try {
            final Map map = (Map) getMember(thread, "this$0.habitat.descriptorsByAdvertisedContract");
            if (map != null) {
                for (final Object v : map.values()) {
                    final Collection list = (Collection) getMember(v, "unsortedList");
                    if (list != null) {
                        for (final Iterator i = list.iterator(); i.hasNext();) {
                            final Object o = i.next();
                            if (o == null)
                                continue;
                            if (o.getClass().getName().equals("org.jvnet.hk2.internal.SystemDescriptor")) {
                                ClassLoader cl = (ClassLoader) getMember(o,
                                        "cachedValue.endpoint.webComponentImpl.webBundleDescriptor.classLoader");
                                if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                    LOG.info("removing from descriptorsByAdvertisedContract: " + o);
                                    i.remove();
                                    continue;
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }

        try {
            final Object cache = getMember(thread, "this$0.habitat.singletonContext.valueCache");
            if (cache != null) {
                final Method clear = cache.getClass().getDeclaredMethod("clear");
                clear.setAccessible(true);
                LOG.info("clearing cache for this$0.habitat.singletonContext.valueCache: " + cache);
                clear.invoke(cache);
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }

        try {
            final Map map = (Map) getMember(thread, "this$0.systemRegistry.moduleDescriptors");
            if (map != null) {
                for (final Object o1 : map.values()) {
                    if (o1 instanceof Map) {
                        for (final Object o2 : ((Map) o1).values()) {
                            if (o2 instanceof Collection) {
                                for (final Object o : ((Collection) o2)) {
                                    final ClassLoader cl = (ClassLoader) getMember(o,
                                            "cachedValue.endpoint.webComponentImpl.webBundleDescriptor.classLoader");
                                    if (refersToMyEar(cl, myClassLoader, myUrlSet)) {
                                        LOG.info("nulling cachedValue: " + o);
                                        setMember(o, "cachedValue", null);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            LOG.error(ex, ex);
        }
    }

    private boolean refersToMyEar(final ClassLoader cl, ClassLoader myClassLoader, Set<Object> myUrlSet) {
        for (ClassLoader current = cl; current != null; current = current.getParent()) {
            if (current == myClassLoader) {
                return true;
            }
            String currentString = current.toString();
            for (Object o : myUrlSet) {
                if (currentString.indexOf(o.toString()) > 0) {

                    for (current = cl; current != null; current = current.getParent()) {
                        try {
                            ArrayList<?> transformers = (ArrayList<?>) getMember(current, "transformers");
                            if (transformers != null) {
                                for (Object spcci : transformers) {
                                    Map<?, ?> classDetailsMap =
                                            (Map<?, ?>) getMember(spcci, "val$transformer.classDetailsMap");
                                    if (classDetailsMap != null)
                                        classDetailsMap.clear();
                                }
                                transformers.clear();
                            }
                        } catch (Exception ignore) {
                        }
                    }

                    // belongs to us -> clear cache
                    ResourceBundle.clearCache(cl);

                    return true;
                }
            }
        }
        return false;
    }
}

rev: 1.1