com.sunchenbin.store.feilong.core.lang.ClassLoaderUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.sunchenbin.store.feilong.core.lang.ClassLoaderUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sunchenbin.store.feilong.core.lang;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sunchenbin.store.feilong.core.io.UncheckedIOException;
import com.sunchenbin.store.feilong.core.tools.jsonlib.JsonUtil;

/**
 * {@link java.lang.ClassLoader}.
 * 
 * <h3>?:</h3>
 * 
 * <blockquote>
 * 
 * <ul>
 * <li>{@link #getResource(String)}</li>
 * <li>{@link #getClassPath()}</li>
 * <li>{@link #getClassPath(ClassLoader)}</li>
 * <li>{@link #getResource(String, Class)}</li>
 * <li>{@link #getResource(ClassLoader, String)}</li>
 * <li>{@link #getResources(String, Class)}</li>
 * </ul>
 * 
 * <p>
 * "",classes 
 * </p>
 * e.q:<br>
 * 
 * <blockquote>
 * <table border="1" cellspacing="0" cellpadding="4">
 * <tr style="background-color:#ccccff">
 * <th align="left"></th>
 * <th align="left">(maven)</th>
 * <th align="left">web(??jar)</th>
 * </tr>
 * <tr valign="top">
 * <td>{@code getResource("")}</td>
 * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/</td>
 * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@code getResource("com")}</td>
 * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/com</td>
 * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/com/</td>
 * </tr>
 * </table>
 * </blockquote>
 * </blockquote>
 * 
 * <h3> {@link java.lang.Class#getResourceAsStream(String) Class#getResourceAsStream(String)} VS
 * {@link java.lang.ClassLoader#getResourceAsStream(String) ClassLoader#getResourceAsStream(String)}</h3>
 * 
 * <blockquote>
 * <p>
 * ,? classpath ???,classpath?classpathclasspathjar
 * </p>
 * <p>
 * ?? src/main/resources?, messages/feilong-core-message_en_US.properties,
 * </p>
 * <ul>
 * <li> {@link java.lang.Class#getResourceAsStream(String) Class#getResourceAsStream(String)} ?
 * <b>"/messages/feilong-core-message_en_US.properties"</b>, ???;<br>
 *  / ,?, ? / , class</li>
 * <li>{@link java.lang.ClassLoader#getResourceAsStream(String) ClassLoader#getResourceAsStream(String)} ?
 * <b>"messages/feilong-core-message_en_US.properties"</b>,ClassLoader JVMBootstrapLoader?.<br>
 * ??"messages/feilong-core-message_en_US.properties" <span style="color:red">??/?</span></li>
 * </ul>
 * 
 * </blockquote>
 *
 * @author feilong
 * @version 1.0 2011-4-27 ?12:40:08
 * @see java.lang.ClassLoader
 * @see java.net.URLClassLoader
 * @since 1.0.0
 */
public final class ClassLoaderUtil {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(ClassLoaderUtil.class);

    /** Don't let anyone instantiate this class. */
    private ClassLoaderUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    /**
     * ???.
     * 
     * <p>
     * "",classes 
     * </p>
     * e.q:<br>
     * 
     * <blockquote>
     * <table border="1" cellspacing="0" cellpadding="4">
     * <tr style="background-color:#ccccff">
     * <th align="left"></th>
     * <th align="left">(maven)</th>
     * <th align="left">web,(??jar)</th>
     * </tr>
     * <tr valign="top">
     * <td>{@code getResource("")}</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/</td>
     * </tr>
     * <tr valign="top" style="background-color:#eeeeff">
     * <td>{@code getResource("com")}</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/com</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/com/</td>
     * </tr>
     * </table>
     * </blockquote>
     *
     * @param resourceName
     *            the resource name
     * @return ???
     */
    public static URL getResource(String resourceName) {
        ClassLoader classLoader = getClassLoaderByClass(ClassLoaderUtil.class);
        return getResource(classLoader, resourceName);
    }

    /**
     *   classpath,?classes.
     * 
     * @return   classpath
     * @see #getResource(String)
     */
    public static URL getClassPath() {
        ClassLoader classLoader = getClassLoaderByClass(ClassLoaderUtil.class);
        return getClassPath(classLoader);
    }

    /**
     *  class path.
     *
     * @param classLoader
     *            the class loader
     * @return the class path
     * @see #getResource(ClassLoader, String)
     */
    public static URL getClassPath(ClassLoader classLoader) {
        return getResource(classLoader, "");
    }

    // *****************************************************
    /**
     * This is a convenience method to load a resource as a stream. <br>
     * The algorithm used to find the resource is given in getResource()
     * 
     * @param resourceName
     *            The name of the resource to load
     * @param callingClass
     *            The Class object of the calling object
     * @return the resource as stream
     * @see #getResource(String, Class)
     * @see "org.apache.velocity.util.ClassUtils#getResourceAsStream(Class, String)"
     */
    public static InputStream getResourceAsStream(String resourceName, Class<?> callingClass) {
        URL url = getResource(resourceName, callingClass);
        try {
            return (url != null) ? url.openStream() : null;
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    /**
     * Load a given resource.
     * <p>
     * This method will try to load the resource using the following methods (in order):
     * </p>
     * <ul>
     * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
     * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
     * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
     * </ul>
     * 
     * @param resourceName
     *            The name of the resource to load
     * @param callingClass
     *            The Class object of the calling object
     * @return the resource
     */
    public static URL getResource(String resourceName, Class<?> callingClass) {
        ClassLoader classLoader = getClassLoaderByCurrentThread();
        URL url = classLoader.getResource(resourceName);
        if (url == null) {
            LOGGER.warn("In ClassLoader:[{}],not found the resourceName:[{}]",
                    JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)), resourceName);

            classLoader = getClassLoaderByClass(ClassLoaderUtil.class);
            url = getResource(classLoader, resourceName);

            if (url == null) {
                LOGGER.warn("In ClassLoader:[{}],not found the resourceName:[{}]",
                        JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)), resourceName);
                classLoader = getClassLoaderByClass(callingClass);
                url = getResource(classLoader, resourceName);
            }
        }
        if (url == null) {
            LOGGER.warn("resourceName:[{}] in all ClassLoader not found", resourceName);
        } else {
            LOGGER.debug("found the resourceName:[{}],In ClassLoader :[{}] ", resourceName,
                    JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)));
        }
        return url;
    }

    /**
     * ???.
     * <p>
     * "",classes 
     * </p>
     * e.q:<br>
     * 
     * <blockquote>
     * <table border="1" cellspacing="0" cellpadding="4">
     * <tr style="background-color:#ccccff">
     * <th align="left"></th>
     * <th align="left">(maven)</th>
     * <th align="left">web,(??jar)</th>
     * </tr>
     * <tr valign="top">
     * <td>{@code getResource("")}</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/</td>
     * </tr>
     * <tr valign="top" style="background-color:#eeeeff">
     * <td>{@code getResource("com")}</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-common/target/test-classes/com</td>
     * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-spring-test-2.5/src/main/webapp/WEB-INF/classes/com/</td>
     * </tr>
     * </table>
     * </blockquote>
     *
     * @param classLoader
     *            the class loader
     * @param resourceName
     *            the resource name
     * @return the resource
     * @since 1.2.1
     */
    public static URL getResource(ClassLoader classLoader, String resourceName) {
        return classLoader.getResource(resourceName);
    }

    /**
     * Load resources.
     * 
     * @param resourceName
     *            the resource name
     * @param callingClass
     *            the calling class
     * @return the resources
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     * @see java.lang.ClassLoader#getResources(String)
     */
    public static Enumeration<URL> getResources(String resourceName, Class<?> callingClass) throws IOException {
        ClassLoader classLoader = getClassLoaderByCurrentThread();
        Enumeration<URL> urls = classLoader.getResources(resourceName);
        if (urls == null) {
            classLoader = getClassLoaderByClass(ClassLoaderUtil.class);
            urls = classLoader.getResources(resourceName);
            if (urls == null) {
                classLoader = getClassLoaderByClass(callingClass);
                urls = classLoader.getResources(resourceName);
            }
        }
        if (urls == null) {
            LOGGER.warn("resourceName:[{}] in all ClassLoader not found!", resourceName);
        } else {
            LOGGER.debug("In ClassLoader :[{}] found the resourceName:[{}]",
                    JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)), resourceName);
        }
        return urls;
    }

    /**
     * Load a class with a given name.
     * 
     * <p>
     * It will try to load the class in the following order:
     * </p>
     * <ul>
     * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
     * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
     * </ul>
     * 
     * <p>
     * Returns the class represented by {@code className} using the {@code classLoader}. <br>
     * This implementation supports the syntaxes " {@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", "
     * {@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;} ".
     * </p>
     * 
     * @param className
     *            The name of the class to load
     * @return the class
     * @throws ClassNotFoundException
     *             If the class cannot be found anywhere.
     * @see java.lang.ClassLoader#loadClass(String)
     * @see java.lang.Class#forName(String)
     * @see java.lang.Class#forName(String, boolean, ClassLoader)
     * @see org.apache.commons.lang3.ClassUtils#getClass(String)
     * @see org.apache.commons.lang3.ClassUtils#getClass(ClassLoader, String, boolean)
     * @see "org.springframework.util.ClassUtils#forName(String, ClassLoader)"
     * @since 1.4.0
     */
    public static Class<?> getClass(String className) throws ClassNotFoundException {
        return org.apache.commons.lang3.ClassUtils.getClass(className);
    }

    /**
     *  {@link Thread#getContextClassLoader()}  {@link ClassLoader}.
     * 
     * @return the class loader by current thread
     */
    public static ClassLoader getClassLoaderByCurrentThread() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Thread.currentThread().getContextClassLoader:{}",
                    JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)));
        }
        return classLoader;
    }

    /**
     * ? {@link ClassLoader}.
     * 
     * @param callingClass
     *            the calling class
     * @return the class loader by class
     * @see java.lang.Class#getClassLoader()
     */
    public static ClassLoader getClassLoaderByClass(Class<?> callingClass) {
        ClassLoader classLoader = callingClass.getClassLoader();
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("{}.getClassLoader():{}", callingClass.getSimpleName(),
                    JsonUtil.format(getClassLoaderInfoMapForLog(classLoader)));
        }
        return classLoader;
    }

    /**
     *  {@link ClassLoader} info map for LOGGER.
     *
     * @param classLoader
     *            the class loader
     * @return the class loader info map for log
     * @since 1.1.1
     */
    private static Map<String, Object> getClassLoaderInfoMapForLog(ClassLoader classLoader) {
        Map<String, Object> classLoaderInfoMap = new LinkedHashMap<String, Object>();
        classLoaderInfoMap.put("classLoader", "" + classLoader);
        classLoaderInfoMap.put("classLoader[CanonicalName]", classLoader.getClass().getCanonicalName());
        classLoaderInfoMap.put("classLoader[Root Classpath]", "" + getClassPath(classLoader));
        return classLoaderInfoMap;
    }
}