001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.xbean.classloader;
018
019import java.util.Map;
020import java.lang.reflect.Field;
021import java.lang.reflect.Method;
022import java.beans.Introspector;
023import java.io.ObjectInputStream;
024import java.io.ObjectOutputStream;
025import java.io.ObjectStreamClass;
026
027/**
028 * Utility methods for class loader manipulation in a server environment.
029 *
030 * @author Dain Sundstrom
031 * @version $Id: ClassLoaderUtil.java 813161 2009-09-09 23:03:32Z djencks $
032 * @since 2.0
033 */
034public final class ClassLoaderUtil {
035    private ClassLoaderUtil() {
036    }
037
038    /**
039     * Cleans well known class loader leaks in VMs and libraries.  There is a lot of bad code out there and this method
040     * will clear up the known problems.  This method should only be called when the class loader will no longer be used.
041     * It this method is called two often it can have a serious impact on preformance.
042     * @param classLoader the class loader to destroy
043     */
044    public static void destroy(ClassLoader classLoader) {
045        releaseCommonsLoggingCache(classLoader);
046        clearSunSoftCache(ObjectInputStream.class, "subclassAudits");
047        clearSunSoftCache(ObjectOutputStream.class, "subclassAudits");
048        clearSunSoftCache(ObjectStreamClass.class, "localDescs");
049        clearSunSoftCache(ObjectStreamClass.class, "reflectors");
050        Introspector.flushCaches();
051    }
052
053    /**
054     * Clears the caches maintained by the SunVM object stream implementation.  This method uses reflection and
055     * setAccessable to obtain access to the Sun cache.  The cache is locked with a synchronize monitor and cleared.
056     * This method completely clears the class loader cache which will impact performance of object serialization.
057     * @param clazz the name of the class containing the cache field
058     * @param fieldName the name of the cache field
059     */
060    public static void clearSunSoftCache(Class clazz, String fieldName) {
061        Map cache = null;
062        try {
063            Field field = clazz.getDeclaredField(fieldName);
064            field.setAccessible(true);
065            cache = (Map) field.get(null);
066        } catch (Throwable ignored) {
067            // there is nothing a user could do about this anyway
068        }
069
070        if (cache != null) {
071            synchronized (cache) {
072                cache.clear();
073            }
074        }
075    }
076
077    /**
078     * Releases the specified classloader from the Apache Jakarta Commons Logging class loader cache using reflection.
079     * @param classLoader the class loader to release
080     */
081    public static void releaseCommonsLoggingCache(ClassLoader classLoader) {
082        try {
083            Class logFactory = classLoader.loadClass("org.apache.commons.logging.LogFactory");
084            Method release = logFactory.getMethod("release", new Class[] {ClassLoader.class});
085            release.invoke(null, new Object[] {classLoader});
086        } catch (Throwable ignored) {
087            // there is nothing a user could do about this anyway
088        }
089    }
090
091}