org.ireland.jnetty.loader.WebAppClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.ireland.jnetty.loader.WebAppClassLoader.java

Source

//
//  ========================================================================
//  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.ireland.jnetty.loader;

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/* ------------------------------------------------------------ */
/**
 * ClassLoader for HttpContext. Specializes URLClassLoader with some utility and file mapping methods.
 * 
 * This loader defaults to the 2.3 servlet spec behavior where non system classes are loaded from the classpath in
 * preference to the parent loader. Java2 compliant loading, where the parent loader always has priority, can be
 * selected with the {@link org.eclipse.jetty.webapp.WebAppContext#setParentLoaderPriority(boolean)} method and
 * influenced with {@link WebAppContext#isServerClass(String)} and {@link WebAppContext#isSystemClass(String)}.
 * 
 * If no parent class loader is provided, then the current thread context classloader will be used. If that is null then
 * the classloader that loaded this class is used as the parent.
 * 
 */
public class WebAppClassLoader extends URLClassLoader {
    private static final Log LOG = LogFactory.getLog(WebAppClassLoader.class);

    private static final boolean isDebugEnabled = LOG.isDebugEnabled();

    //Default: SystemClassLoader
    private final ClassLoader _parent;

    private String _name = String.valueOf(hashCode());

    /**
     * Should this class loader delegate to the parent class loader <strong>before</strong> searching its own
     * repositories (i.e. the usual Java2 delegation model)? If set to <code>false</code>, this class loader will search
     * its own repositories first, and delegate to the parent only if the class or resource is not found locally. Note
     * that the default, <code>false</code>, is the behavior called for by the servlet specification.
     */
    protected boolean delegate = true;

    /* ------------------------------------------------------------ */
    /**
     * Constructor.
     */
    public WebAppClassLoader() throws IOException {
        this(null);
    }

    /* ------------------------------------------------------------ */
    /**
     * Constructor.
     */
    public WebAppClassLoader(ClassLoader parent) throws IOException {
        super(new URL[] {},
                parent != null ? parent
                        : (Thread.currentThread().getContextClassLoader() != null
                                ? Thread.currentThread().getContextClassLoader()
                                : (WebAppClassLoader.class.getClassLoader() != null
                                        ? WebAppClassLoader.class.getClassLoader()
                                        : ClassLoader.getSystemClassLoader())));

        _parent = getParent();

        if (_parent == null)
            throw new IllegalArgumentException("no parent classloader!");
    }

    /* ------------------------------------------------------------ */
    /**
     * @return the name of the classloader
     */
    public String getName() {
        return _name;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param name
     *            the name of the classloader
     */
    public void setName(String name) {
        _name = name;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param classPath
     *            Comma or semicolon separated path of filenames or URLs pointing to directories or jar files.
     *            Directories should end with '/'.
     */
    public void addClassPath(URL classPath) {
        addURL(classPath);
    }

    /* ------------------------------------------------------------ */
    /**
     * Add elements to the class path for the context from the jar and zip files found in the specified resource.
     * 
     * @param lib
     *            the resource that contains the jar and/or zip files.
     */
    public void addJar(URL jarFile) {
        addURL(jarFile);
    }

    /* ------------------------------------------------------------ */
    @Override
    public Enumeration<URL> getResources(String name) throws IOException {
        List<URL> from_parent = toList(_parent.getResources(name));
        List<URL> from_webapp = toList(this.findResources(name));

        if (delegate) {
            from_parent.addAll(from_webapp);
            return Collections.enumeration(from_parent);
        }

        from_webapp.addAll(from_parent);
        return Collections.enumeration(from_webapp);
    }

    /* ------------------------------------------------------------ */
    private List<URL> toList(Enumeration<URL> e) {
        if (e == null)
            return new ArrayList<URL>();
        return Collections.list(e);
    }

    /* ------------------------------------------------------------ */
    /**
     * Get a resource from the classloader
     * 
     */
    @Override
    public URL getResource(String name) {
        URL url = null;

        // (1) Delegate to parent if requested
        if (delegate) {
            url = _parent.getResource(name);

            if (url != null) {

                if (isDebugEnabled)
                    LOG.debug("  --> Returning '" + url.toString() + "' from parent classloader: " + _parent);

                return (url);
            }
        }

        // (2) Search local resources
        url = this.findResource(name);

        if (url != null) {

            if (isDebugEnabled)
                LOG.debug("  --> Returning '" + url.toString() + "' from " + toString());

            return (url);
        }

        // (3) Delegate to parent unconditionally if not already attempted
        if (!delegate) {
            url = _parent.getResource(name);

            if (url != null) {

                if (isDebugEnabled)
                    LOG.debug("  --> Returning '" + url.toString() + "' from parent classloader: " + _parent);

                return (url);
            }
        }

        // (4) Resource was not found
        if (isDebugEnabled)
            LOG.debug("  --> Resource not found, returning null");
        return (null);
    }

    /* ------------------------------------------------------------ */
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    /* ------------------------------------------------------------ */
    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = loadClass0(name);

        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);

            return (clazz);
        }

        throw new ClassNotFoundException(name);
    }

    /**
     * Load class but not resolve
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    protected synchronized Class<?> loadClass0(String name) throws ClassNotFoundException {
        // (0) Check our previously loaded class cache

        Class<?> clazz = findLoadedClass(name);

        if (clazz != null) {
            //if (isDebugEnabled) LOG.debug("  Returning class from cache,class: "+clazz);

            return (clazz);
        }

        // (1) Delegate to our parent if requested
        if (delegate) {
            if (isDebugEnabled)
                LOG.debug("  Delegating to parent classloader1: " + _parent);

            ClassLoader loader = _parent;
            try {
                clazz = Class.forName(name, false, loader);
                if (clazz != null) {
                    if (isDebugEnabled)
                        LOG.debug("  Loaded class from parent,class: " + clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
        }

        // (2) Search local resources
        if (isDebugEnabled)
            LOG.debug("  Searching local ClassPaths @ " + name);

        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (isDebugEnabled)
                    LOG.debug("  Loaded class from local ClassPaths,class: " + clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        // (3) Delegate to parent unconditionally
        if (!delegate) {
            if (isDebugEnabled)
                LOG.debug("  Delegating to parent classloader at end: " + _parent);

            ClassLoader loader = _parent;

            try {
                clazz = Class.forName(name, false, loader);
                if (clazz != null) {
                    if (isDebugEnabled)
                        LOG.debug("  Loaded class from parent,class: " + clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
        }

        throw new ClassNotFoundException(name);
    }

    /* ------------------------------------------------------------ */
    @Override
    public String toString() {
        return "WebAppClassLoader=" + _name + "@" + Long.toHexString(hashCode());
    }
}