You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/05/19 07:18:20 UTC

svn commit: r407715 [2/2] - in /tomcat/sandbox: ./ java/org/apache/coyote/adapters/ java/org/apache/coyote/http11/ java/org/apache/coyote/http11/apr/ java/org/apache/coyote/standalone/ java/org/apache/tomcat/util/loader/ java/org/apache/tomcat/util/net...

Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java Thu May 18 22:18:18 2006
@@ -0,0 +1,480 @@
+/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+
+/**
+ * A group of modules and libraries. 
+ * 
+ * Modules can have one or more jars and class dirs. Classloaders are created 
+ * from modules when the module is started are be disposed when the module is stopped.
+ * 
+ * The module will delegate to the associated repository in addition to the 
+ * normal delegation rules. The repository will search on all sibling modules.
+ * This mechanism is defined in the MLetClassLoader and is also used by JBoss and
+ * few other servers. 
+ * 
+ * TODO: explain more ( or point to the right jboss/mlet pages )
+ * TODO: explain how this can be used for webapps to support better partitioning 
+ *
+ * @author Costin Manolache
+ */
+public class Repository {
+   
+    private static final boolean DEBUG=Loader.getProperty("loader.debug.Repository") != null;
+    
+    // Allows the (experimental) use of jar indexes
+    // Right now ( for small set of jars, incomplete build ) it's a tiny 3.5 -> 3.4 sec dif.
+    private static final boolean USE_IDX=Loader.getProperty("loader.Repository.noIndex") == null;
+    
+    private Vector loaders=new Vector();
+    private String name;
+    private Vector grpModules=new Vector();
+    private transient Loader loader;
+    
+    private transient RepositoryClassLoader groupClassLoader;
+    private Hashtable prefixes=new Hashtable();
+
+    // For delegation
+    private ClassLoader parentClassLoader;
+    private Repository parent;
+
+
+    private Repository() {
+    }
+
+    public Repository(Loader loader) {
+        if( loader== null ) throw new NullPointerException();
+        this.loader=loader;
+    }
+
+    public Loader getLoader() {
+        return loader;
+    }
+    
+    void addModule(  Module mod ) {
+        mod.setRepository( this );
+
+        grpModules.addElement(mod);
+        if( loader.listener!=null ) {
+            loader.listener.moduleAdd(mod);
+        }
+        
+        if( parentClassLoader != null ) 
+            mod.setParentClassLoader( parentClassLoader );
+
+        if(! mod.isStarted()) {
+            mod.start();
+            //log("started " + mod);
+        } else {
+            //log("already started " + mod);
+        }
+        
+        try {
+            if( USE_IDX ) {
+                processJarIndex(mod);
+                // TODO: if we are in the initial starting, write cache only once
+                // TODO: write it only if there is a change in the timestamp
+                writeCacheIdx();
+            }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        
+    }
+    
+    public void newModule( String path ) {
+        Module m=new Module();
+        m.setPath( path );
+        addModule( m );
+    }
+    
+    public Enumeration getModules() {
+        return grpModules.elements();
+    }
+    
+    /** Reload any module that is modified
+     */
+    public void checkReload() {
+        try {
+        Enumeration mE=grpModules.elements();
+        while( mE.hasMoreElements() ) {
+            Module m=(Module)mE.nextElement();
+            boolean modif=m.modified();
+            log("Modified " + m + " " + modif);
+            
+            if( modif ) {
+                m.stop();
+                m.start();
+            }
+        }
+        } catch( Throwable t ) {
+            t.printStackTrace();
+        }
+    }
+
+    /** Verify if any module is modified. This is a deep search, including dirs.
+     *  Expensive operation.
+     *  
+     * @return
+     */
+    public boolean isModified() {
+        try {
+            Enumeration mE=grpModules.elements();
+            while( mE.hasMoreElements() ) {
+                Module m=(Module)mE.nextElement();
+                boolean modif=m.modified();
+                log("Modified " + m + " " + modif);
+                if( modif ) return true;
+            }
+        } catch( Throwable t ) {
+            t.printStackTrace();
+        }
+        return false;
+    }
+    
+    Repository getParent() {
+        return parent;
+    }
+    
+    public String toString() {
+        return "Repository " + name + "(" + getClasspathString() + ")";
+    }
+
+    private String getClasspathString() {
+        StringBuffer sb=new StringBuffer();
+        Enumeration mE=grpModules.elements();
+        while( mE.hasMoreElements() ) {
+            Module m=(Module)mE.nextElement();
+            sb.append( m.getClasspathString() + ":");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 
+     * @param parent The parent group
+     */
+    public void setParent(Repository parent) {
+        this.parent = parent;
+    }
+    
+    /** Set the parent class loader - can be used instead of setParent, 
+     * in case this is the top loader and needs to delagate to embedding app
+     * 
+     * @param myL
+     */
+    public void setParentClassLoader(ClassLoader myL) {
+        this.parentClassLoader=myL;
+    }
+
+
+    /** Add a class loder to the group.
+     *
+     *  If this is a StandardClassLoader instance, it will be able to delegate
+     * to the group.
+     *
+     *  If it's a regular ClassLoader - it'll be searched for classes, but
+     * it will not be able to delegate to peers.
+     *
+     * In future we may fine tune this by using manifests.
+     */
+    void addClassLoader(ClassLoader cl ) {
+        if( ( cl instanceof ModuleClassLoader )) {
+            ((ModuleClassLoader)cl).setRepository(this);
+        }
+        loaders.addElement(cl);
+        //    log("Adding classloader " + cl);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void removeClassLoader(ClassLoader cl) {
+        int oldSize=loaders.size();
+        loaders.removeElement(cl);
+
+        if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": "  + cl);
+        // TODO: remove from index
+    }
+
+    /** Return a class loader associated with the group.
+     *  This will delegate to all modules in the group, then to parent.
+     * 
+     * @return
+     */
+    public ClassLoader getClassLoader() {
+        if( groupClassLoader==null ) {
+            
+            ClassLoader pcl=parentClassLoader;
+            if( pcl==null && parent!=null ) {
+                pcl=parent.getClassLoader();
+            } 
+            if( pcl==null ) {
+                pcl=Thread.currentThread().getContextClassLoader();
+             }
+
+            if( pcl == null ) {
+                // allow delegation to embedding app
+                groupClassLoader=new RepositoryClassLoader(new URL[0], this);
+            } else {
+                groupClassLoader=new RepositoryClassLoader(new URL[0], pcl, this);
+            }
+            if( DEBUG ) log("---------- Created repository loader " + pcl );
+        }
+        return groupClassLoader;
+    }
+    
+    /** 
+     * Find a class in the group. It'll iterate over each loader
+     * and try to find the class - using only the method that
+     * search locally or on parent ( i.e. not in group, to avoid
+     * recursivity ).
+     *
+     *
+     * @param classN
+     * @return
+     */
+    Class findClass(ClassLoader caller, String classN ) {
+        Class clazz=null;
+        
+        // do we have it in index ?
+        if( USE_IDX ) {
+            int lastIdx=classN.lastIndexOf(".");
+            String prefix=(lastIdx>0) ? classN.substring(0, lastIdx) : classN;
+            Object mO=prefixes.get(prefix.replace('.', '/'));
+            if( mO!=null ) {
+                if( mO instanceof Module ) {
+                    Module m=(Module)mO;
+                    try {
+                        Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+                        //log("Prefix: " +prefix + " " + classN  + " " + m);
+                        return c;
+                    } catch (Exception e) {
+                        //log("Prefix err: " +prefix + " " + classN  + " " + m + " " + e);
+                        //return null;
+                    }
+                } else {
+                    Module mA[]=(Module[])mO;
+                    for( int i=0; i<mA.length; i++ ) {
+                        Module m=mA[i];
+                        try {
+                            Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+                            //log("Prefix: " +prefix + " " + classN  + " " + m);
+                            return c;
+                        } catch (Exception e) {
+                            //log("Prefix err: " +prefix + " " + classN  + " " + m + " " + e);
+                            //return null;
+                        }
+                    }
+                }
+            }
+        }
+
+        // TODO: move the vector to a []
+        for( int i=loaders.size()-1; i>=0; i-- ) {
+            
+            // TODO: for regular CL, just use loadClass, they'll not recurse
+            // The behavior for non-SCL or not in the group loader is the same as for parent loader
+            ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+            // TODO: move loaders with index in separate vector
+            //if( cl.getModule().hasIndex ) continue;
+            if( cl== caller ) continue;
+            //if( classN.indexOf("SmtpCoyoteProtocolHandler") > 0 ) {
+            //log("try " + cl.debugObj + " " + name + " " + classN + " " + loaders.size());
+            //}
+            try {
+                if( cl instanceof ModuleClassLoader ) {
+                    clazz=((ModuleClassLoader)cl).findLocalClass(classN );
+                } else {
+                    clazz=cl.findClass(classN);
+                }
+
+                //System.err.println("GRPLD: " + classN + " from " + info.get(cl));
+                return clazz;
+            } catch (ClassNotFoundException e) {
+                //System.err.println("CNF: " + classN + " " + info.get(cl) );
+                //if( classN.indexOf("smtp") > 0 ) e.printStackTrace();
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @param loader
+     * @param name2
+     * @return
+     */
+    URL findResource(ModuleClassLoader caller, String classN) {
+        URL url=null;
+        if( DEBUG ) log("Repository.findResource " + classN + " " + caller );
+        for( int i=loaders.size()-1; i>=0; i-- ) {
+            // TODO: for regular CL, just use loadClass, they'll not recurse
+            // The behavior for non-SCL or not in the group loader is the same as for parent loader
+            ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+            if( cl== caller ) continue;
+            url=((ModuleClassLoader)cl).findResource(classN );
+            if( url!=null )
+                return url;
+        }
+        return null;
+    }
+
+    private void log(String s) {
+        System.err.println("Repository (" + name + "): " + s );
+    }
+
+    /**
+     * @param name2
+     */
+    public void setName(String name2) {
+        this.name=name2;
+    }
+
+    /*
+     * Work in progress: 
+     * 
+     * -use the INDEX.LIST to get prefixes to avoid linear
+     * search in repositories.
+     * 
+     * - serialize the state ( including timestamps ) to improve startup time
+     * ( avoids the need to open all jars - if INDEX.LIST is ok)
+     */
+    
+    /**
+     * Read the index. The index contain packages and top level resources
+     * 
+     * @param cl
+     * @throws Exception
+     */
+    private void processJarIndex(Module m) throws Exception {
+        ModuleClassLoader cl=(ModuleClassLoader)m.createClassLoader();
+        // only support index for modules with a single jar in CP
+        String cp=m.getClasspathString();
+        if( ! cp.endsWith(".jar")) return;
+        URL urlIdx=cl.findResource("META-INF/INDEX.LIST");
+        if( urlIdx == null ) {
+            log("INDEX.LIST not found, run: jar -i " + m.getClasspathString());
+            return;
+        }
+        try {
+            InputStream is=urlIdx.openStream();
+            if( is==null ) {
+                log("Can't read " + urlIdx + " " + m.getClasspathString());
+                return;
+            }
+            BufferedReader br=new BufferedReader( new InputStreamReader(is) );
+            String line=br.readLine();
+            if( line==null ) return;
+            if( ! line.startsWith( "JarIndex-Version:") ||  
+                    ! line.endsWith("1.0")) {
+                log("Invalid signature " + line + " " + m.getClasspathString());
+            }
+            br.readLine(); // ""
+            
+            while( readSection(br, m) ) {
+            }
+           
+            m.hasIndex=true;
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    
+    private boolean readSection( BufferedReader br, Module m) throws IOException {
+        String jarName=br.readLine();
+        if( jarName==null ) return false; // done
+        if( "".equals( jarName )) {
+            log("Invalid jarName " + jarName + " " + m.getClasspathString() );
+            return false;
+        }
+        //log("Index " + jarName + " " + m.getClasspathString());
+        String prefix=null;
+        while( ((prefix=br.readLine()) != null ) && 
+                (! "".equals( prefix )) ) {
+            //log("found " + prefix + " " + m);
+            Object o=prefixes.get(prefix);
+            if( o == null ) {
+                prefixes.put(prefix, m);
+            } else {
+                Module mA[]=null;
+                if( o instanceof Module ) {
+                    mA=new Module[2];
+                    mA[0]=(Module)o;
+                    mA[1]=m;
+                } else {
+                    Object oldA[]=(Module[])o;
+                    mA=new Module[oldA.length + 1];
+                    System.arraycopy(oldA, 0, mA, 0, oldA.length);
+                    mA[oldA.length]=m;
+                }
+                prefixes.put( prefix, mA);
+                //log("Multiple prefixes: " + prefix + " " + mA);
+                
+            }
+        }
+        
+        return prefix!=null;
+    }
+
+
+    /** Read loader.REPO.cache from work dir
+     * 
+     * This file will hold timestamps for each module/jar and cache the INDEX -
+     * to avoid opening the jars/modules that are not used 
+     * 
+     * @throws IOException
+     */
+    private void readCachedIdx() throws IOException {
+        
+    }
+    
+    /** Check the index and verify that:
+     * - all jars are older than timestamp and still exist
+     * - there are no new jars 
+     * 
+     * @throws IOException
+     */
+    private void checkCacheIdx() throws IOException {
+        
+    }
+    
+    
+    private void writeCacheIdx() throws IOException {
+        // For each module we write the timestamp, filename then the index
+        // The idea is to load this single file to avoid scanning many jars
+
+        // we'll use the cache 
+        
+        
+    }
+
+}

Propchange: tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java
------------------------------------------------------------------------------
    svn:executable = *

Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java Thu May 18 22:18:18 2006
@@ -0,0 +1,253 @@
+/*
+ * 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;
+
+/**
+ * Class loader associated with a repository ( common, shared, server, etc ). 
+ *
+ * This class loader will never load any class by itself ( since it has no repository ),
+ * it will just delegate to modules. 
+ * 
+ * Refactored as a separate class to make the code cleaner.
+ * Based on catalina loader.
+ *   
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class RepositoryClassLoader
+    extends URLClassLoader
+{
+    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 RepositoryClassLoader(URL repositories[], ClassLoader parent, Repository lg) {
+        super(repositories, parent);
+        this.repository=lg;
+    }
+    
+
+    public RepositoryClassLoader(URL repositories[], Repository lg) {
+        super(repositories);
+        this.repository=lg;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private Repository repository;
+
+    // ---------------------------------------------------- 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 {
+
+        Class clazz = null;
+        
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).findClass2(name, false);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( name );
+
+    }
+    
+    /** 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
+    {
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).findLocalClass(name);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( 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) {
+        URL url = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                url=((ModuleClassLoader)m.getClassLoader()).findResource2(name, false);
+                if( url!= null ) {
+                    return url;
+                }
+        }
+        
+        if (url==null && DEBUG) {
+            if (DEBUGNF) log("findResource() NOTFOUND " + name );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Return an enumeration of <code>URLs</code> representing all of the
+     * resources with the given name.  If no resources with this name are
+     * found, return an empty enumeration.
+     *
+     * @param name Name of the resources to be found
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public Enumeration findResources(String name) throws IOException {
+        Vector result=new Vector();
+        
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                Enumeration myRes=((ModuleClassLoader)m.getClassLoader()).findResources2(name,false);
+                if( myRes!=null ) {
+                    while( myRes.hasMoreElements() ) {
+                        result.addElement(myRes.nextElement());
+                    }
+                }
+        }
+        
+        return result.elements();
+
+    }
+
+    // Next methods implement the search alghoritm - parent, repo, delegation, etc 
+
+    /** getResource() - modified to implement the search alghoritm 
+     * 
+     */
+    public URL getResource(String name) {
+        URL url = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                url=((ModuleClassLoader)m.getClassLoader()).getResource2(name, null, false);
+                if( url!= null ) {
+                    return url;
+                }
+        }
+        
+        if (url==null && DEBUG) {
+            if (DEBUGNF) log("findResource() NOTFOUND " + name );
+        }
+
+        return null;
+    }
+    
+    /**
+     * Load the class with the specified name, searching using the following
+     * algorithm until it finds and returns the class.  If the class cannot
+     * be found, returns <code>ClassNotFoundException</code>.
+     * <ul>
+     * <li>Call <code>findLoadedClass(String)</code> to check if the
+     *     class has already been loaded.  If it has, the same
+     *     <code>Class</code> object is returned.</li>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>loadClass()</code> method of the parent class
+     *     loader, if any.</li>
+     * <li>Call <code>findClass()</code> to find this class in our locally
+     *     defined repositories.</li>
+     * <li>Call the <code>loadClass()</code> method of our parent
+     *     class loader, if any.</li>
+     * </ul>
+     * If the class was found using the above steps, and the
+     * <code>resolve</code> flag is <code>true</code>, this method will then
+     * call <code>resolveClass(Class)</code> on the resulting Class object.
+     *
+     * @param name Name of the class to be loaded
+     * @param resolve If <code>true</code> then resolve the class
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+
+        Class clazz = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).loadClass2(name, resolve, false);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( name );
+
+    }
+
+
+    // ------------------ Local methods ------------------------
+
+    private void log(String s ) {
+        System.err.println("RepositoryClassLoader: " + s);
+    }
+    private void log(String s, Throwable t ) {
+        System.err.println("RepositoryClassLoader: " + s);
+        t.printStackTrace();
+    }
+
+}
+

Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html Thu May 18 22:18:18 2006
@@ -0,0 +1,32 @@
+<html>
+<body>
+
+The goal of this package is to provide class loading functionality, similar in behavior with Jboss and MLET loaders. There 
+is no specific policy, just a mechanism - how it is used depends on the application. It is based on the tomcat5.x class
+loader, with additional support for the 'repository' delegation.
+
+The main class is Loader - it controls a hierarchy of Repositories, each consisting of one or more Modules. Each Module corresponds to one jar file 
+or directory - and will have a ModuleClassLoader that answers only for that file. The Repository is associated with a ModuleClassLoader that delegates to 
+each Module. It is possible to add/remove/replace Modules at runtime - just like in JMX and JBoss. In normal tomcat, only webapps can be reloaded - this also allow connectors, valves, and any internal server jar to be reloaded.
+
+The package only deals with class loading, with minimal the dependencies. Currently there is no dependency except bare JDK1.3. 
+
+The modules and loaders can be registered with JMX by a module using the ModuleListener, after jmx class loader is created. Note that JMX is not a dependency and doesn't have to be in the classpath - it can be loaded in a Repository, and then something like Modeler will do the mapping. 
+
+Configuration uses a simple properties file describing the classpaths and the classes to launch - i.e. all a class loader needs to know, and similar with the old catalina.properties. 
+
+To implement a good module system on top of this we need lifecycle ( already present in tomcat ) and discipline in making sure there are no stale references to  objects in a module after its death. 
+
+An OSGI-like system may seem to deal with the second problem - but it doesn't solve anything, it just makes 
+the references more visible and requires major changes in how you code, as well as rewriting of most apis and implementations - and in the end it still 
+doesn't solve the problem. JBoss and JMX are actually on the right track in this, as oposed to OSGI. 
+
+The loader is also trying to stick to the minimal classloading-related functionality - unlike OSGI wich is reinventing all weels. I started working on the loader after trying to see how OSGI would fit, and realizing that it is a wrong design.
+
+
+<h2>Using loader for launching</h2>
+
+Loader has a main(), and will look up the loader.properties file, create the class loaders, and then launch any 'auto-startup' classes. The must important part of launching an app is setting the classpath, and using Loader allows the app to use more advanced features than using simple CLASSPATH.
+
+</body>
+</html>
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org