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; } }