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     */
017    package org.apache.xbean.classloader;
018    
019    import java.util.Map;
020    import java.lang.reflect.Field;
021    import java.lang.reflect.Method;
022    import java.beans.Introspector;
023    import java.io.ObjectInputStream;
024    import java.io.ObjectOutputStream;
025    import 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 437551 2006-08-28 06:14:47Z adc $
032     * @since 2.0
033     */
034    public 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 know 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 preformance 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    }