Modified: 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Repository.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Repository.java?view=diff&rev=534293&r1=534292&r2=534293
==============================================================================
--- 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Repository.java 
(original)
+++ 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/loader/Repository.java 
Tue May  1 19:22:45 2007
@@ -14,314 +14,220 @@
  * limitations under the License.
  */
 
-
 package org.apache.tomcat.util.loader;
 
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Vector;
 
-
 /**
- * A group of modules.  
- * 
- * Modules can have one or more jars and classes dirs, and are reloaded as a 
- * unit. Each module has an internal class loader.
- * 
- * The module will delegate to the associated repository in addition to the 
- * normal delegation rules. The repository will search on all sibling modules.
+ * Class loader similar with the MLetClassLoader and JBoss - it maintains a 
list
+ * of 'modules' ( similar with mbeans - a single jar or dir ), each of them can
+ * be reloaded independently, without reloading the whole repository.
  * 
- * This mechanism is defined in the MLetClassLoader and is also used by JBoss 
- * and few other servers.
- * 
- *  Use: 
- *   - create a Repository in all situations where you would need a separate
- *     class loader - each webapp, common/, server/, etc.
- *   - set the parent hierarchy
- *   - add modules to each repo - a module can be a single jar/classes, or 
- *     multiple jars. I think single jar modules may be better.  
- *   - get the classloader from repository 
+ * This works well as long as the interface between modules don't change - it 
is
+ * a bit better than hot-reloading of classes, which requires each class method
+ * signatures to be unchanged.
  * 
  * @author Costin Manolache
  */
 public class Repository {
-   
-    private static final boolean 
DEBUG=System.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=System.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;
+    // Use jar indexes. Most loaders don't - it's a small optimization,
+    // but it's a good practice.
+    private static final boolean USE_IDX = true;
 
+    Vector loaders = new Vector();
 
-    public Repository() {
-    }
+    private RepositoryClassLoader groupClassLoader;
 
-    public void addModule(  Module mod ) {
-        mod.setRepository( this );
+    private ClassLoader parent;
 
-        grpModules.addElement(mod);
-        
-        if( parentClassLoader != null ) 
-            mod.setParentClassLoader( parentClassLoader );
+    // From jar index: package -> Module or Module[]
+    private Hashtable prefixes = new Hashtable();
+
+    // Collects all jars without INDEX.LIST.
+    private ArrayList missingIndexList = new ArrayList();
 
-        if(! mod.isStarted()) {
-            mod.start();
+    /**
+     * Should this class loader delegate to the parent class loader
+     * <strong>before</strong> searching its own repositories (i.e. the usual
+     * Java2 delegation model)? 
+     */
+    private boolean delegate = true;
+
+    public Repository() {
+        this(null, null, true);
+    }
+    
+    public Repository(URL[] cp, ClassLoader parent) {
+        this(cp, parent, true);
+    }
+
+    public Repository(URL[] cp, ClassLoader parent, boolean delegate) {
+        if (parent == null) {
+            parent = Thread.currentThread().getContextClassLoader();
         }
-        
-        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();
+        this.parent = parent;
+        if (cp != null) {
+            for (int i = 0; i < cp.length; i++) {
+                addURL(cp[i]);
             }
-        } 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();
+
+    public void setParentClassLoader(ClassLoader myL) {
+        this.parent = myL;
     }
     
-    /** Reload any module that is modified
+    /**
+     * Return a class loader associated with the group. This will delegate to
+     * all modules in the group, then to parent.
      */
-    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();
+    public URLClassLoader getClassLoader() {
+        if (groupClassLoader == null) {
+            if (parent == null) {
+                groupClassLoader = new RepositoryClassLoader(new URL[0], this);
+            } else {
+                groupClassLoader = new RepositoryClassLoader(new URL[0], 
parent,
+                        this);
             }
         }
-        } catch( Throwable t ) {
-            t.printStackTrace();
-        }
+        return groupClassLoader;
     }
 
-    /** 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;
+    public void addURL(URL url) {
+        ModuleClassLoader mod = new ModuleClassLoader(new URL[] { url },
+                parent, delegate, this);
+        addModuleClassLoader(mod);
     }
     
-    Repository getParent() {
-        return parent;
+    public void addURL(URL[] url) {
+        for (int i = 0; i < url.length; i++) {
+            addURL(url[i]);
+        }
     }
     
-    public String toString() {
-        return "Repository " + name + "(" + getClasspathString() + ")";
+    Enumeration getModules() {
+        return loaders.elements();
     }
-
-    public String getClasspathString() {
-        StringBuffer sb=new StringBuffer();
-        Enumeration mE=grpModules.elements();
-        while( mE.hasMoreElements() ) {
-            Module m=(Module)mE.nextElement();
-            sb.append( m.getClasspathString() + ":");
+    
+    ModuleClassLoader createClassLoader(URL[] classpath) throws Exception {
+        ModuleClassLoader classLoader = null;
+        if (parent == null) {
+            parent = Thread.currentThread().getContextClassLoader();
         }
-        return sb.toString();
+        classLoader = new ModuleClassLoader(classpath, parent,
+                delegate, this);
+
+        loaders.addElement(classLoader);
+
+        return classLoader;
     }
 
     /**
+     * Verify if any module is modified. This is a deep search, including dirs.
      * 
-     * @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.
+     * @return
      */
-    void addClassLoader(ClassLoader cl ) {
-        if( ( cl instanceof ModuleClassLoader )) {
-            ((ModuleClassLoader)cl).setRepository(this);
+    public boolean isModified() {
+        try {
+            Enumeration mE = loaders.elements();
+            while (mE.hasMoreElements()) {
+                ModuleClassLoader m = (ModuleClassLoader) mE.nextElement();
+                boolean modif = m.modified();
+                if (modif)
+                    return true;
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
         }
-        loaders.addElement(cl);
-        //    log("Adding classloader " + cl);
-    }
-
-    public String getName() {
-        return name;
+        return false;
     }
 
-    public void removeClassLoader(ClassLoader cl) {
-        int oldSize=loaders.size();
-        loaders.removeElement(cl);
-
-        if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": "  + 
cl);
-        // TODO: remove from index
+    public String toString() {
+        return "Repository " + "(" + getClasspathString() + ")";
     }
 
-    /** 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);
+    public String getClasspathString() {
+        StringBuffer sb = new StringBuffer();
+        Enumeration mE = loaders.elements();
+        while (mE.hasMoreElements()) {
+            ModuleClassLoader m = (ModuleClassLoader) mE.nextElement();
+            URL[] urls = m.getURLs();
+            for (int i = 0; i < urls.length; i++) {
+                sb.append(urls[i].getFile()).append(":");
             }
-            if( DEBUG ) log("---------- Created repository loader " + pcl );
         }
-        return groupClassLoader;
+        return sb.toString();
     }
 
-    public void addDir(File directory) {
-        try {
-            URL url=directory.toURL();
-            Module mod = new Module();
-            mod.setClasspath(new URL[] {url});
-            addModule(mod);
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
-        }
 
-    }
-    
-    public void addLibs(File directory) {
-        if (!directory.isDirectory() || !directory.exists() ||
-                !directory.canRead()) {
-            if (DEBUG)
-                log("  Not found:  "+ directory.getAbsolutePath());
-            return;
-        }
-        String filenames[] = directory.list();
-        for (int j = 0; j < filenames.length; j++) {
-            String filename = filenames[j].toLowerCase();
-            if (!filename.endsWith(".jar"))
-                continue;
-            File file = new File(directory, filenames[j]);
-            try {
-                URL url=file.toURL();
-                Module mod = new Module();
-                mod.setClasspath(new URL[] {url});
-                addModule(mod);
-            } catch (MalformedURLException e) {
-                e.printStackTrace();
+
+    void addModuleClassLoader(ModuleClassLoader mod) {
+        loaders.addElement(mod);
+        try {
+            if (USE_IDX) {
+                processJarIndex(mod);
             }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
         }
     }
-    
-    /** 
-     * 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 ).
-     *
-     *
+
+    /**
+     * 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;
-        
+    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;
+        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 ModuleClassLoader) {
+                    ModuleClassLoader m = (ModuleClassLoader) mO;
                     try {
-                        Class 
c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
-                        //log("Prefix: " +prefix + " " + classN  + " " + m);
+                        Class c = m.findLocalClass(classN);
+                        // log("Prefix: " +prefix + " " + classN + " " + m);
                         return c;
                     } catch (Exception e) {
-                        //log("Prefix err: " +prefix + " " + classN  + " " + m 
+ " " + e);
-                        //return null;
+                        // 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];
+                    ModuleClassLoader mA[] = (ModuleClassLoader[]) mO;
+                    for (int i = 0; i < mA.length; i++) {
+                        ModuleClassLoader m = mA[i];
                         try {
-                            Class 
c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
-                            //log("Prefix: " +prefix + " " + classN  + " " + 
m);
+                            Class c = m.findLocalClass(classN);
+                            // log("Prefix: " +prefix + " " + classN + " " + 
m);
                             return c;
                         } catch (Exception e) {
-                            //log("Prefix err: " +prefix + " " + classN  + " " 
+ m + " " + e);
-                            //return null;
+                            // log("Prefix err: " +prefix + " " + classN + " " 
+
+                            // m + " " + e);
+                            // return null;
                         }
                     }
                 }
@@ -329,185 +235,592 @@
         }
 
         // TODO: move the vector to a []
-        for( int i=loaders.size()-1; i>=0; i-- ) {
-            
+        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);
+            // 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());
-            //}
+            // 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 );
+                if (cl instanceof ModuleClassLoader) {
+                    clazz = ((ModuleClassLoader) cl).findLocalClass(classN);
                 } else {
-                    clazz=cl.findClass(classN);
+                    clazz = cl.findClass(classN);
                 }
 
-                //System.err.println("GRPLD: " + classN + " from " + 
info.get(cl));
+                // 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();
+                // 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-- ) {
+        URL url = null;
+        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 )
+            // 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 );
+    public Class findClass(String name) throws ClassNotFoundException {
+        Enumeration modulesE = getModules();
+        while (modulesE.hasMoreElements()) {
+            try {
+                ModuleClassLoader m = (ModuleClassLoader) modulesE
+                        .nextElement();
+                return m.findClass2(name, false);
+            } catch (ClassNotFoundException ex) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException(name);
+    }
+
+    public URL findResource(final String name) {
+        URL url = null;
+        Enumeration modulesE = getModules();
+        while (modulesE.hasMoreElements()) {
+            ModuleClassLoader m = (ModuleClassLoader) modulesE.nextElement();
+            url = m.findResource2(name, false);
+            if (url != null) {
+                return url;
+            }
+        }
+        return null;
+    }
+
+    public Enumeration findResources(String name) throws IOException {
+        Vector result = new Vector();
+
+        Enumeration modulesE = getModules();
+        while (modulesE.hasMoreElements()) {
+            ModuleClassLoader m = (ModuleClassLoader) modulesE.nextElement();
+            Enumeration myRes = m.findResources2(name, false);
+            if (myRes != null) {
+                while (myRes.hasMoreElements()) {
+                    result.addElement(myRes.nextElement());
+                }
+            }
+        }
+
+        return result.elements();
+    }
+
+    public URL getResource(String name) {
+
+        URL url = null;
+        Enumeration modulesE = getModules();
+        while (modulesE.hasMoreElements()) {
+            ModuleClassLoader m = (ModuleClassLoader) modulesE.nextElement();
+            url = m.getResource2(name, null, false);
+            if (url != null) {
+                return url;
+            }
+        }
+
+        return null;
+    }
+
+    public Class loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+
+        Enumeration modulesE = getModules();
+        while (modulesE.hasMoreElements()) {
+            try {
+                ModuleClassLoader m = (ModuleClassLoader) modulesE
+                        .nextElement();
+                return m.loadClass2(name, resolve, false);
+            } catch (ClassNotFoundException ex) {
+                // ignore
+            }
+        }
+
+        throw new ClassNotFoundException(name);
     }
 
+
     /**
-     * @param name2
+     * Reload any module that is modified
      */
-    public void setName(String name2) {
-        this.name=name2;
+    public void checkReload() {
+        try {
+            Enumeration mE = loaders.elements();
+            ArrayList toReload = null;
+            while (mE.hasMoreElements()) {
+                ModuleClassLoader m = (ModuleClassLoader) mE.nextElement();
+                boolean modif = m.modified();
+                if (modif) {
+                    toReload = new ArrayList();
+                    toReload.add(m);
+                }
+            }
+            Iterator reloadIt = toReload.iterator();
+            while (reloadIt.hasNext()) {
+                ModuleClassLoader m = (ModuleClassLoader) reloadIt.next();
+                URL[] cp = m.getURLs();
+                loaders.removeElement(m);
+                missingIndexList.remove(m);
+                if (prefixes.containsValue(m)) {
+                    ArrayList toRemove = new ArrayList();
+                    Iterator prefI = prefixes.entrySet().iterator();
+                    while (prefI.hasNext()) {
+                        Map.Entry entry = (Map.Entry) prefI.next();
+                        if (entry.getValue() == m) {
+                            toRemove.add(entry.getKey());
+                        }
+                    }
+                    prefI = toRemove.iterator();
+                    while (prefI.hasNext()) {
+                        prefixes.remove(prefI.next());
+                    }
+                }
+
+                m = createClassLoader(cp);
+                loaders.addElement(m);
+            }
+
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
     }
 
-    // Collects all jars without INDEX.LIST. Can be used for debugging.
-    public static Map missingIndexList = new HashMap();
-    
-    /*
-     * 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 ) {
-            missingIndexList.put(cp, "1");
+    private void processJarIndex(ModuleClassLoader cl) throws Exception {
+        String cp = cl.getURLs()[0].toString();
+        if (!cp.endsWith(".jar")) {
+            missingIndexList.add(cl);
+            return;
+        }
+
+        // ModuleClassLoader cl = (ModuleClassLoader) m.createClassLoader();
+        URL urlIdx = cl.findResource("META-INF/INDEX.LIST");
+        if (urlIdx == null) {
+            missingIndexList.add(cl);
             return;
         }
+
         try {
-            InputStream is=urlIdx.openStream();
-            if( is==null ) {
-                log("Can't read " + urlIdx + " " + m.getClasspathString());
+            InputStream is = urlIdx.openStream();
+            if (is == null) {
+                missingIndexList.add(cl);
+                return;
+            }
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String line = br.readLine();
+            if (line == null) {
+                missingIndexList.add(cl);
                 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());
+            if (!line.startsWith("JarIndex-Version:") || 
!line.endsWith("1.0")) {
+                missingIndexList.add(cl);
+                return;
             }
             br.readLine(); // ""
-            
-            while( readSection(br, m) ) {
+            while (readSection(br, cl)) {
             }
-           
-            m.hasIndex=true;
         } catch (IOException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            missingIndexList.add(cl);
         }
     }
-    
-    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 ) {
+
+    private boolean readSection(BufferedReader br, ModuleClassLoader m)
+            throws IOException {
+        String jarName = br.readLine();
+        if (jarName == null)
+            return false; // done
+        if ("".equals(jarName)) {
+            throw new IOException("Invalid jarName " + jarName);
+        }
+
+        String prefix = null;
+        while (((prefix = br.readLine()) != null) && (!"".equals(prefix))) {
+            Object o = prefixes.get(prefix);
+            if (o == null) {
+                // Common case
                 prefixes.put(prefix, m);
             } else {
-                Module mA[]=null;
-                if( o instanceof Module ) {
-                    mA=new Module[2];
-                    mA[0]=(Module)o;
-                    mA[1]=m;
+                ModuleClassLoader mA[] = null;
+                if (o instanceof ModuleClassLoader) {
+                    mA = new ModuleClassLoader[2];
+                    mA[0] = (ModuleClassLoader) o;
+                    mA[1] = m;
                 } else {
-                    Object oldA[]=(Module[])o;
-                    mA=new Module[oldA.length + 1];
+                    Object oldA[] = (ModuleClassLoader[]) o;
+                    mA = new ModuleClassLoader[oldA.length + 1];
                     System.arraycopy(oldA, 0, mA, 0, oldA.length);
-                    mA[oldA.length]=m;
+                    mA[oldA.length] = m;
                 }
-                prefixes.put( prefix, mA);
-                //log("Multiple prefixes: " + prefix + " " + mA);
-                
+                prefixes.put(prefix, mA);
             }
         }
-        
-        return prefix!=null;
+        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 
+    /**
+     * Class loader associated with a repository.
      * 
-     * @throws IOException
+     * This class loader will never load any class by itself it will just
+     * delegate to modules.
      */
-    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
+    static class RepositoryClassLoader extends URLClassLoader {
 
-        // we'll use the cache 
-        
+        private Repository repository;
+
+        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;
+        }
         
+        public void addURL(URL url) {
+            repository.addURL(url);
+        }
+
+        public Class findClass(String name) throws ClassNotFoundException {
+            return repository.findClass(name);
+        }
+
+        public URL findResource(final String name) {
+            return repository.findResource(name);
+        }
+
+        public Enumeration findResources(String name) throws IOException {
+            return repository.findResources(name);
+        }
+
+        public URL getResource(String name) {
+            return repository.getResource(name);
+        }
+
+        public Class loadClass(String name, boolean resolve)
+                throws ClassNotFoundException {
+            return repository.loadClass(name, resolve);
+        }
     }
 
+    static class ModuleClassLoader extends URLClassLoader {
+        public ModuleClassLoader(URL repositories[], ClassLoader parent,
+                boolean delegate, Repository lg) {
+            super(repositories, parent);
+            this.delegate = delegate;
+            this.repository = lg;
+            lastModified = System.currentTimeMillis();
+        }
+
+        protected long lastModified = 0L;
+
+        protected Repository repository;
+
+        protected boolean delegate = false;
+
+        // ---------------------------------------------------- ClassLoader
+        // Methods
+
+        public Class findClass(String name) throws ClassNotFoundException {
+            return findClass2(name, true);
+        }
+
+        public Class findClass2(String name, boolean del2repo)
+                throws ClassNotFoundException {
+            if (del2repo) {
+                return repository.findClass(name);
+            }
+            Class clazz = super.findClass(name);
+            // if( clazz.getClassLoader() != this )
+            // log("findClass() FOUND " + clazz + " Loaded by " +
+            // clazz.getClassLoader());
+            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.
+         */
+        public Class findLocalClass(String name) throws ClassNotFoundException 
{
+            Class clazz = findLoadedClass(name);
+            if (clazz != null) {
+                return (clazz);
+            }
+            return findClass(name);
+        }
+
+        public URL findResource(final String name) {
+            return findResource2(name, true);
+        }
+
+        public URL findResource2(final String name, boolean del2repo) {
+            if (del2repo) {
+                return repository.findResource(name);
+            }
+            return super.findResource(name);
+        }
+
+        public Enumeration findResources(String name) throws IOException {
+            return findResources2(name, true);
+        }
+
+        Enumeration findResources2(String name, boolean del2repo)
+                throws IOException {
+            if (del2repo) {
+                return repository.findResources(name);
+            }
+            return super.findResources(name);
+        }
+
+        public URL getResource(String name) {
+            return getResource2(name, null, true);
+        }
+
+        /**
+         * getResource() - same thing, but don't delegate to repo if called 
from
+         * repo
+         */
+        URL getResource2(String name, ClassLoader originator,
+                         boolean delegate2repo) {
+
+            URL url = null;
+
+            // (1) Delegate to parent if requested
+            if (delegate) {
+                url = getResourceParentDelegate(name);
+                if (url != null)
+                    return url;
+            }
+
+            // (2) Search local repositories
+            url = findResource(name);
+            if (url != null) {
+                // TODO: antijar locking - WebappClassLoader is making
+                // a copy ( is it ??)
+                // log("getResource() found locally " + delegate + " " +
+                // name + " " + url);
+                return (url);
+            }
+
+            // (3) load from one of the classes in the group
+            if (delegate2repo && repository != null) {
+                url = repository.findResource(this, name);
+                if (url != null) {
+                    // log("getResource() FOUND from group " +
+                    // repository.getName()
+                    // + " " + name + " " + url);
+                    return url;
+                }
+            }
+
+            // (4) Delegate to parent unconditionally if not already attempted
+            if (!delegate) {
+                url = getResourceParentDelegate(name);
+                if (url != null)
+                    return url;
+            }
+
+            // (5) Resource was not found
+            return (null);
+
+        }
+
+        // TODO: repository should handle this !
+        // to avoid duplication - get resource from parent, when delegating
+        private URL getResourceParentDelegate(String name) {
+            URL url = null;
+            ClassLoader loader = getParent();
+
+            if (loader == null) {
+                loader = getSystemClassLoader();
+            }
+            url = loader.getResource(name);
+            if (url != null) {
+                // log("getResource() found by system " + delegate + " " +
+                // name + " " + url);
+                return (url);
+            }
+            return url;
+        }
+
+        public Class loadClass(String name, boolean resolve)
+                throws ClassNotFoundException {
+            return loadClass2(name, resolve, true);
+        }
+
+        public Class loadClass2(String name, boolean resolve, boolean del2repo)
+                throws ClassNotFoundException {
+
+            Class clazz = null;
+
+            // (0) Check our previously loaded local class cache
+            clazz = findLoadedClass(name);
+            if (clazz != null) {
+                if (resolve)
+                    resolveClass(clazz);
+                return (clazz);
+            }
+
+            // (1) Try loading the class with the system class loader, to
+            // prevent
+            // the webapp from overriding J2SE classes
+            try {
+                clazz = getSystemClassLoader().loadClass(name);
+                if (clazz != null) {
+                    if (resolve)
+                        resolveClass(clazz);
+                    return (clazz);
+                }
+            } catch (ClassNotFoundException e) {
+            }
+
+            // TODO: delegate based on filter
+            boolean delegateLoad = delegate;// || filter(name);
+
+            // (1) Delegate to our parent if requested
+            if (delegateLoad) {
+                ClassLoader loader = getParent();
+                if (loader != null) {
+                    try {
+                        clazz = loader.loadClass(name);
+                        if (clazz != null) {
+                            // log("loadClass() FOUND by parent " + delegate + 
"
+                            // "
+                            // + name + " , " + resolve);
+                            if (resolve)
+                                resolveClass(clazz);
+                            return (clazz);
+                        }
+                    } catch (ClassNotFoundException e) {
+                    }
+                }
+            }
+
+            // (2) Search local repositories
+            try {
+                clazz = findClass(name);
+                if (clazz != null) {
+                    // log("loadClass - FOUND findClass " + delegate + " " +
+                    // name + " , " + resolve);
+                    if (resolve)
+                        resolveClass(clazz);
+                    return (clazz);
+                }
+            } catch (ClassNotFoundException e) {
+            }
+
+            // (3) Other peer loaders
+            if (del2repo && repository != null) {
+                Class cls = repository.findClass(this, name);
+                if (cls != null) {
+                    // log("loadClass(): FOUND from group " +
+                    // repository.getName()
+                    // + " " + name);
+                    if (resolve)
+                        resolveClass(clazz);
+                    return cls;
+                }
+            }
+
+            // (4) Delegate to parent unconditionally
+            if (!delegateLoad) {
+                ClassLoader loader = getParent();
+                if (loader != null) {
+                    try {
+                        clazz = loader.loadClass(name);
+                        if (clazz != null) {
+                            // log("loadClass() FOUND parent " + delegate + " "
+                            // +
+                            // name + " , " + resolve);
+                            if (resolve)
+                                resolveClass(clazz);
+                            return (clazz);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        ;
+                    }
+                }
+            }
+            throw new ClassNotFoundException(name);
+        }
+
+        /**
+         * Have one or more classes or resources been modified so that a reload
+         * is appropriate?
+         */
+        boolean modified() {
+            URL cp[] = getURLs();
+            if (cp != null) {
+                for (int i = 0; i < cp.length; i++) {
+                    // assume dirs are used only for debug and small
+                    File f = new File(cp[i].getFile());
+                    if (f.isDirectory()) {
+                        return null != dirCheck(f, 10);
+                    } else {
+                        long lm = f.lastModified();
+                        if (lm > lastModified) {
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            return (false);
+        }
+
+        private File dirCheck(File dir, int level) {
+            File subd[] = dir.listFiles();
+            for (int i = 0; i < subd.length; i++) {
+                if (subd[i].isDirectory() && level > 0) {
+                    return dirCheck(subd[i], level - 1);
+                } else {
+                    long lm = subd[i].lastModified();
+                    if (lm > lastModified) {
+                        return subd[i];
+                    }
+                }
+            }
+            return null;
+        }
+    }
 }

Added: 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/res/StringManager.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/res/StringManager.java?view=auto&rev=534293
==============================================================================
--- 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/res/StringManager.java 
(added)
+++ 
tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/res/StringManager.java 
Tue May  1 19:22:45 2007
@@ -0,0 +1,283 @@
+/*
+ *  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.res;
+
+import java.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * An internationalization / localization helper class which reduces
+ * the bother of handling ResourceBundles and takes care of the
+ * common cases of message formating which otherwise require the
+ * creation of Object arrays and such.
+ *
+ * <p>The StringManager operates on a package basis. One StringManager
+ * per package can be created and accessed via the getManager method
+ * call.
+ *
+ * <p>The StringManager will look for a ResourceBundle named by
+ * the package name given plus the suffix of "LocalStrings". In
+ * practice, this means that the localized information will be contained
+ * in a LocalStrings.properties file located in the package
+ * directory of the classpath.
+ *
+ * <p>Please see the documentation for java.util.ResourceBundle for
+ * more information.
+ *
+ * @author James Duncan Davidson [EMAIL PROTECTED]
+ * @author James Todd [EMAIL PROTECTED]
+ * @author Mel Martinez [EMAIL PROTECTED]
+ * @see java.util.ResourceBundle
+ */
+
+public class StringManager {
+
+    /**
+     * The ResourceBundle for this StringManager.
+     */
+
+    private ResourceBundle bundle;
+    private Locale locale;
+
+    /**
+     * Creates a new StringManager for a given package. This is a
+     * private method and all access to it is arbitrated by the
+     * static getManager method call so that only one StringManager
+     * per package will be created.
+     *
+     * @param packageName Name of package to create StringManager for.
+     */
+
+    private StringManager(String packageName) {
+       this( packageName, Locale.getDefault() );
+    }
+
+    private StringManager(String packageName, Locale loc) {
+        String bundleName = packageName + ".LocalStrings";
+        bundle = ResourceBundle.getBundle(bundleName, loc);
+        // Get the actual locale, which may be different from the requested one
+        locale = bundle.getLocale();
+    }
+
+    private StringManager(ResourceBundle bundle )
+    {
+       this.bundle=bundle;
+        locale = bundle.getLocale();
+    }
+
+    /**
+        Get a string from the underlying resource bundle or return
+        null if the String is not found.
+     
+        @param key to desired resource String
+        @return resource String matching <i>key</i> from underlying
+                bundle or null if not found.
+        @throws IllegalArgumentException if <i>key</i> is null.        
+     */
+
+    public String getString(String key) {
+        if(key == null){
+            String msg = "key may not have a null value";
+
+            throw new IllegalArgumentException(msg);
+        }
+
+        String str = null;
+
+        try{
+               str = bundle.getString(key);
+        }catch(MissingResourceException mre){
+            //bad: shouldn't mask an exception the following way:
+            //   str = "[cannot find message associated with key '" + key + "' 
due to " + mre + "]";
+               //     because it hides the fact that the String was missing
+               //     from the calling code.
+               //good: could just throw the exception (or wrap it in another)
+               //      but that would probably cause much havoc on existing
+               //      code.
+               //better: consistent with container pattern to
+               //      simply return null.  Calling code can then do
+               //      a null check.
+               str = null;
+        }
+
+        return str;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format
+     * it with the given set of arguments.
+     *
+     * @param key
+     * @param args
+     */
+
+    public String getString(String key, Object[] args) {
+        String iString = null;
+        String value = getString(key);
+
+        // this check for the runtime exception is some pre 1.1.6
+        // VM's don't do an automatic toString() on the passed in
+        // objects and barf out
+
+        try {
+            // ensure the arguments are not null so pre 1.2 VM's don't barf
+            if(args==null){
+                args = new Object[1];
+            }
+            
+            Object[] nonNullArgs = args;
+            for (int i=0; i<args.length; i++) {
+                if (args[i] == null) {
+                    if (nonNullArgs==args){
+                        nonNullArgs=(Object[])args.clone();
+                    }
+                    nonNullArgs[i] = "null";
+                }
+            }
+            if( value==null ) value=key;
+           MessageFormat mf = new MessageFormat(value);
+            mf.setLocale(locale);
+            iString = mf.format(nonNullArgs, new StringBuffer(), 
null).toString();
+        } catch (IllegalArgumentException iae) {
+            StringBuffer buf = new StringBuffer();
+            buf.append(value);
+            for (int i = 0; i < args.length; i++) {
+                buf.append(" arg[" + i + "]=" + args[i]);
+            }
+            iString = buf.toString();
+        }
+        return iString;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object argument. This argument can of course be
+     * a String object.
+     *
+     * @param key
+     * @param arg
+     */
+
+    public String getString(String key, Object arg) {
+       Object[] args = new Object[] {arg};
+       return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     */
+
+    public String getString(String key, Object arg1, Object arg2) {
+       Object[] args = new Object[] {arg1, arg2};
+       return getString(key, args);
+    }
+    
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                           Object arg3) {
+       Object[] args = new Object[] {arg1, arg2, arg3};
+       return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     * @param arg4
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                           Object arg3, Object arg4) {
+       Object[] args = new Object[] {arg1, arg2, arg3, arg4};
+       return getString(key, args);
+    }
+    // --------------------------------------------------------------
+    // STATIC SUPPORT METHODS
+    // --------------------------------------------------------------
+
+    private static Hashtable managers = new Hashtable();
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param packageName The package name
+     */
+    public synchronized static StringManager getManager(String packageName) {
+      StringManager mgr = (StringManager)managers.get(packageName);
+      if (mgr == null) {
+          mgr = new StringManager(packageName);
+          managers.put(packageName, mgr);
+      }
+      return mgr;
+    }
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param bundle The resource bundle
+     */
+    public synchronized static StringManager getManager(ResourceBundle bundle) 
{
+      return new StringManager( bundle );
+    }
+
+    /**
+     * Get the StringManager for a particular package and Locale. If a manager 
for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created for that Locale and returned.
+     *
+     * @param packageName The package name
+     * @param loc The locale
+     */
+
+   public synchronized static StringManager getManager(String 
packageName,Locale loc) {
+      StringManager mgr = 
(StringManager)managers.get(packageName+"_"+loc.toString());
+      if (mgr == null) {
+          mgr = new StringManager(packageName,loc);
+          managers.put(packageName+"_"+loc.toString(), mgr);
+      }
+      return mgr;
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to