⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 moduleclassloader.java

📁 精通tomcat书籍原代码,希望大家共同学习
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 1999,2004 The Apache Software Foundation.
 * 
 * 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.apache.tomcat.util.loader;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.Vector;

/*
 * Initially, I started with WebappClassLoader attempting to clean up and
 * refactor it. Because of complexity and very weird ( and likely buggy ) 
 * behavior, I moved the other way, starting with URLClassLoader and adding
 * the functionality from WebappClassLoader. 
 * 
 * The current version has a lot of unimplemented WebappClassLoader features and
 * TODOs - all of them are needed in order to support a single/consistent loader
 * for webapps and server/modules. 
 * 
 * - all ordering options and tricks
 * - local loading - in case it can be made more efficient than URLCL
 * - hook to plugin JNDI finder
 * - ability to add extra permissions to loaded classes
 * - ability to use work dir for anti-jar locking and generated classes ( incl getURLs)
 * 
 * 
 * Things better kept out:
 *  - negative cache - it'll waste space with little benefit, most not found classes
 *  will not be asked multiple times, and most will be in other loaders
 *  - binaryContent cache - it's unlikely same resource will be loaded multiple
 * times, and some may be large  
 * 
 */

/**
 * Simple module class loader. Will search the repository if the class is not
 * found locally.
 * 
 * TODO: findResources() - merge all responses from the repo and parent. 
 *
 * Based on StandardClassLoader and WebappClassLoader.
 *   
 * @author Costin Manolache
 * @author Remy Maucherat
 * @author Craig R. McClanahan
 */
public class ModuleClassLoader
    extends URLClassLoader
{
    // Don't use commons logging or configs to debug loading - logging is dependent
    // on loaders and drags a lot of stuff in the classpath 
    //
    private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.debug.ModuleClassLoader") != null;
    private static final boolean DEBUGNF=false;//LoaderProperties.getProperty("loader.debug.ModuleClassLoaderNF") != null;
    
    // ----------------------------------------------------------- Constructors


    public ModuleClassLoader(URL repositories[], ClassLoader parent) {
        super(repositories, parent);
        if(DEBUG) log( "NEW ModuleClassLoader  " + parent + " " + repositories.length);
        updateStamp();
    }
    

    public ModuleClassLoader(URL repositories[]) {
        super(repositories);
        if(DEBUG) log( "NEW ModuleClassLoader  -null-"+ " " + repositories.length);
        updateStamp();
    }


    // ----------------------------------------------------- Instance Variables

    protected Repository repository;

    /**
     * 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.
     */
    protected boolean delegate = false;

    /**
     * Last time a JAR was accessed. 
     * TODO: change to last time the loader was accessed
     */
    protected long lastJarAccessed = 0L;

    protected long lastModified=0L;
    
    /**
     * Has this component been started?
     */
    protected boolean started = false;

    protected Module module;

    // ------------------------------------------------------------- Properties

    /**
     * Set the "delegate first" flag for this class loader.
     *
     * @param delegate The new "delegate first" flag
     */
    void setDelegate(boolean delegate) {
        this.delegate = delegate;
    }

    void setRepository(Repository lg ) {
        this.repository=lg;
    }

    void setModule(Module webappLoader) {
        this.module=webappLoader;
    }

    /** Not public - his can only be called from package.
     *  To get the module from a ClassLoader you need access to the Loader
     * instance.
     * 
     * @return
     */
    Module getModule() {
        return module;
    }

    void setWorkDir(File s) {
        // TODO
    }

    /**
     * Add a new repository to the set of places this ClassLoader can look for
     * classes to be loaded.
     *
     * @param repository Name of a source of classes to be loaded, such as a
     *  directory pathname, a JAR file pathname, or a ZIP file pathname
     *
     * @exception IllegalArgumentException if the specified repository is
     *  invalid or does not exist
     */
    void addRepository(String repository) {
        // Add this repository to our underlying class loader
        try {
            boolean mod=modified();
            URL url = new URL(repository);
            super.addURL(url);
            if( ! mod ) {
                // don't check if it is modified, so it works
                updateStamp();
            }
        } catch (MalformedURLException e) {
            IllegalArgumentException iae = new IllegalArgumentException
                ("Invalid repository: " + repository); 
            iae.initCause(e);
            //jdkCompat.chainException(iae, e);
            throw iae;
        }
    }

    void updateStamp() {
        URL cp[]=super.getURLs();
        if (cp != null ) {
            for (int i = 0; i <cp.length; i++) {
                File f=new File(cp[i].getFile());
                long lm=f.lastModified();
                if( lm > lastModified ) lastModified=lm;
            }
        }
    }
    
    private boolean dirCheck(File dir ) {
        //log("Checking " + dir );
        File subd[]=dir.listFiles();
        for( int i=0; i< subd.length; i++ ) {
            long lm=subd[i].lastModified();
            if( lm > lastModified ) {
                log("Modified file: " + dir + " " + subd[i] + " " + lm + " " + lastModified);
                return true;
            }
            if( subd[i].isDirectory() ) {
                return  dirCheck(subd[i]);
            }
        }
        return false;
    }
    
    /**
     * Have one or more classes or resources been modified so that a reload
     * is appropriate?
     * 
     * Not public - call it via Module
     */
    boolean modified() {
        URL cp[]=super.getURLs();
        if (cp != null ) {
            for (int i = 0; i <cp.length; i++) {
                File f=new File(cp[i].getFile());
                long lm=f.lastModified();
                if( lm > lastModified ) {
                    log( "Modified file: " + f + " " + lm + " " + lastModified);
                    return true;
                }
                // assume dirs are used only for debug and small
                if( f.isDirectory() ) {
                    return dirCheck(f);
                }
            }
        }

        if (DEBUG)
            log("modified() false");

        // TODO - check at least the jars 
        return (false);
    }

    // ---------------------------------------------------- ClassLoader Methods


    /**
     * Find the specified class in our local repositories, if possible.  If
     * not found, throw <code>ClassNotFoundException</code>.
     *
     * @param name Name of the class to be loaded
     *
     * @exception ClassNotFoundException if the class was not found
     */
    public Class findClass(String name) throws ClassNotFoundException {
        return findClass2(name, true);
    }
    
    public Class findClass2(String name, boolean del2repo) throws ClassNotFoundException {
        if( del2repo ) {
            return ((RepositoryClassLoader)repository.getClassLoader()).findClass(name);            
        } // else 
 
        Class clazz = null;
            
        try {
            clazz = super.findClass(name);
        } catch (RuntimeException e) {
            if (DEBUG)
                log("findClass() -->RuntimeException " + name, e);
            throw e;
        } catch( ClassNotFoundException ex ) {
            URL cp[]=this.getURLs();
            if (DEBUGNF)
                log("findClass() NOTFOUND  " + name + " " + (( cp.length > 0 ) ? cp[0].toString() : "") );
            throw ex;
        }
            
        if (clazz == null) { // does it ever happen ? 
            if (DEBUGNF)
                log("findClass() NOTFOUND throw CNFE " + name);
            throw new ClassNotFoundException(name);
        }

        // Return the class we have located
        if (DEBUG) {
            if( clazz.getClassLoader() != this ) 
                log("findClass() FOUND " + clazz + " Loaded by " + clazz.getClassLoader());
            else 
                log("findClass() FOUND " + clazz );
        }
        return (clazz);
    }
    
    /** Same as findClass, but also checks if the class has been previously 
     * loaded.
     * 
     * In most implementations, findClass() doesn't check with findLoadedClass().
     * In order to implement repository, we need to ask each loader in the group
     * to load only from it's local resources - however this will lead to errors
     * ( duplicated definition ) if findClass() is used.
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    public Class findLocalClass(String name) throws ClassNotFoundException
    {
        Class clazz = findLoadedClass(name);
        if (clazz != null) {
            if (DEBUG)
                log("findLocalClass() - FOUND " + name);
            return (clazz);
        }
        
        return findClass(name);
    }



    
    /**
     * Find the specified resource in our local repository, and return a
     * <code>URL</code> refering to it, or <code>null</code> if this resource
     * cannot be found.
     *
     * @param name Name of the resource to be found
     */
    public URL findResource(final String name) {
        return findResource2( name, true);
    }
        
    public URL findResource2(final String name, boolean del2repo ) {
        if( del2repo ) {
            return ((RepositoryClassLoader)repository.getClassLoader()).findResource(name);
        } // else:

        URL url = null;

        url = super.findResource(name);
        
        if(url==null) {
            // try the repository
            // TODO
        }
        
        if (url==null && DEBUG) {
            if (DEBUGNF) log("findResource() NOTFOUND " + name );
            return null;
        }

        if (DEBUG) log("findResource() found " + name + " " + url );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -