org.impalaframework.classloader.BaseURLClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.impalaframework.classloader.BaseURLClassLoader.java

Source

/*
 * Copyright 2007-2010 the original author or authors.
 * 
 * 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 org.impalaframework.classloader;

import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.impalaframework.util.URLUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * {@link ClassLoader} which resolves a particular class or resource from one of
 * a set of locations on the file system. Note that this class is abstract as it
 * does not override the superclass's <code>loadClass()</code> method.
 * 
 * @author Phil Zoio
 */
public abstract class BaseURLClassLoader extends java.net.URLClassLoader {

    private static final Log logger = LogFactory.getLog(BaseURLClassLoader.class);

    private Map<String, Class<?>> loadedClasses = new ConcurrentHashMap<String, Class<?>>();

    private URL[] urls;

    /**
     * Constructs this class loader with a set of <code>File</code> locations
     * from which the class can be be loaded
     */
    public BaseURLClassLoader(File[] locations) {
        this(URLUtils.createUrls(locations));
    }

    /**
     * As with the overloaded constructor, except that it provides a parent
     * <code>ClassLoader</code>.
     */
    public BaseURLClassLoader(ClassLoader parent, File[] locations) {
        this(parent, URLUtils.createUrls(locations));
    }

    /**
     * Constructs this class loader with a set of <code>URL</code> locations
     * from which the class can be be loaded
     */
    public BaseURLClassLoader(URL[] locations) {
        super(locations);
        this.urls = locations;
    }

    /**
     * As with the overloaded constructor, except that it provides a parent
     * <code>ClassLoader</code>.
     */
    public BaseURLClassLoader(ClassLoader parent, URL[] locations) {
        super(locations, parent);
        this.urls = locations;
    }

    /**
     * Attempts to load class from one of the locations supplied via a
     * constructor. Designed to be used by subclasses.
     * @param className name of class to load
     * @return a <code>Class</code> instance, if the class could be loaded,
     * otherwise null.
     */
    protected Class<?> loadCustomClass(String className) {
        try {
            Class<?> foundClass = super.findClass(className);
            if (logger.isInfoEnabled()) {
                logger.info("Found class " + className + " using class loader " + this);
            }
            loadedClasses.put(className, foundClass);
            return foundClass;
        } catch (ClassNotFoundException e1) {
            return null;
        }
    }

    /**
     * Returns a cached <code>Class</code> instance, if it has already been
     * loaded using the <code>ClassLoader</code>. Designed to be used by
     * subclasses.
     * @param className the name of the class to return
     * @return returns the cached <code>Class</code> instance, if previously
     * loaded using this <code>ClassLoader</code>, otherwise null.
     */
    protected Class<?> getAlreadyLoadedClass(String className) {
        Class<?> loadedClass = loadedClasses.get(className);
        if (loadedClass != null) {
            if (logger.isDebugEnabled()) {
                debug("Returning already loaded custom class: " + className);
            }
            return loadedClass;
        }
        return loadedClass;
    }

    /**
     * Attempts to load the designated class by delegating to the parent class
     * loader.
     * @param className the name of the class to load
     * @return a <code>Class</code> instance successfully loaded, otherwise
     * null
     */
    protected Class<?> loadParentClass(String className) {
        try {
            Class<?> parentClass = getParent().loadClass(className);

            if (logger.isDebugEnabled()) {
                debug("Returning from parent class loader: " + getParent() + ": " + parentClass);
            }

            return parentClass;
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Attempt to load a resoure, first by calling
     * <code>getCustomResource</code>. If the resource is not found
     * <code>super.getResource(name)</code> is called.
     */
    @Override
    public URL getResource(String name) {

        final URL url = getCustomResource(name);
        if (url != null) {
            return url;
        }

        return super.getResource(name);
    }

    /**
     * Attempts to find a resource from one of the file system locations
     * specified in a constructor.
     * @param name the name of the resource to load
     * @return a <code>URL</code> instance, if the resource can be found,
     * otherwise null.
     */
    protected URL getCustomResource(String name) {
        return super.findResource(name);
    }

    /**
     * Returns an immutable map of name to <code>Class</code> instances loaded
     * via this class loader
     * @return
     */
    public Map<String, Class<?>> getLoadedClasses() {
        return Collections.unmodifiableMap(loadedClasses);
    }

    private void debug(String message) {
        logger.debug(this.getClass().getSimpleName() + "[" + System.identityHashCode(this) + "]: " + message);
    }

    @Override
    public String toString() {
        return super.toString() + ", URLS: " + Arrays.toString(urls) + ", parent: "
                + (getParent() != null ? getParent().toString() : " ");
    }

}