I'm posting this for comments.

In libgcj we have a divergence in URLClassLoader, because we have
other ways to load classes.  In particular we can extract classes
from shared libraries via 'gcjlib' URLs, and URLClassLoader knows
about this.

I'd like to re-merge here so that we have one less divergence to carry
around.

This patch allows this by moving the URLLoader class, and friends, to
gnu.java.net.loader.  Then it changes URLClassLoader to look for
other loaders via reflection.  This will let us add new URLLoader
subclasses in the libgcj tree and have things work properly.

Tom

2006-05-14  Tom Tromey  <[EMAIL PROTECTED]>

        * java/net/URLClassLoader.java: Moved inner classes to
        gnu.java.net.loader.
        (factoryCache): Changed type.
        (URL_LOADER_PREFIX): New constant.
        (URLClassLoader): Updated for new factoryCache.
        (addURLImpl): Use reflection to search for a loader.
        (findClass): Use getClass method on URLLoader.
        (getURLStreamHandler): Removed.
        * gnu/java/net/loader/URLLoader.java: New file, extracted
        from URLClasLoader.
        * gnu/java/net/loader/Resource.java: Likewise.
        * gnu/java/net/loader/FileResource.java: Likewise.
        * gnu/java/net/loader/FileURLLoaderjava: Likewise.
        * gnu/java/net/loader/JarURLLoader.java: Likewise.
        * gnu/java/net/loader/JarURLResource.java: Likewise.
        * gnu/java/net/loader/RemoteURLLoader.java: Likewise.
        * gnu/java/net/loader/RemoteResource.java: Likewise.
        * gnu/java/net/loader/ULRStreamHandlerCache.java: New file.

Index: java/net/URLClassLoader.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/URLClassLoader.java,v
retrieving revision 1.49
diff -u -r1.49 URLClassLoader.java
--- java/net/URLClassLoader.java        8 May 2006 21:30:06 -0000       1.49
+++ java/net/URLClassLoader.java        14 May 2006 21:12:13 -0000
@@ -39,15 +39,21 @@
 
 package java.net;
 
-import gnu.java.net.IndexListParser;
+import gnu.java.net.loader.FileURLLoader;
+import gnu.java.net.loader.JarURLLoader;
+import gnu.java.net.loader.RemoteURLLoader;
+import gnu.java.net.loader.Resource;
+import gnu.java.net.loader.URLLoader;
+import gnu.java.net.loader.URLStreamHandlerCache;
 
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.CodeSource;
@@ -55,15 +61,11 @@
 import java.security.PrivilegedAction;
 import java.security.SecureClassLoader;
 import java.security.cert.Certificate;
-import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 
 
@@ -139,9 +141,15 @@
   /**
    * A cache to store mappings between handler factory and its
    * private protocol handler cache (also a HashMap), so we can avoid
-   * create handlers each time the same protocol comes.
+   * creating handlers each time the same protocol comes.
    */
-  private static HashMap factoryCache = new HashMap(5);
+  private static URLStreamHandlerCache factoryCache
+    = new URLStreamHandlerCache();
+
+  /**
+   * The prefix for URL loaders.
+   */
+  private static final String URL_LOADER_PREFIX = "gnu.java.net.loader.Load_";
 
   // Instance variables
 
@@ -169,494 +177,6 @@
   // Helper classes
 
   /**
-   * A <code>URLLoader</code> contains all logic to load resources from a
-   * given base <code>URL</code>.
-   */
-  abstract static class URLLoader
-  {
-    /**
-     * Our classloader to get info from if needed.
-     */
-    final URLClassLoader classloader;
-
-    /**
-     * The base URL from which all resources are loaded.
-     */
-    final URL baseURL;
-
-    /**
-     * A <code>CodeSource</code> without any associated certificates.
-     * It is common for classes to not have certificates associated
-     * with them.  If they come from the same <code>URLLoader</code>
-     * then it is safe to share the associated <code>CodeSource</code>
-     * between them since <code>CodeSource</code> is immutable.
-     */
-    final CodeSource noCertCodeSource;
-
-    URLLoader(URLClassLoader classloader, URL baseURL)
-    {
-      this(classloader, baseURL, baseURL);
-    }
-
-    URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL)
-    {
-      this.classloader = classloader;
-      this.baseURL = baseURL;
-      this.noCertCodeSource = new CodeSource(overrideURL, null);
-    }
-
-    /**
-     * Returns a <code>Resource</code> loaded by this
-     * <code>URLLoader</code>, or <code>null</code> when no
-     * <code>Resource</code> with the given name exists.
-     */
-    abstract Resource getResource(String s);
-
-    /**
-     * Returns the <code>Manifest</code> associated with the
-     * <code>Resource</code>s loaded by this <code>URLLoader</code> or
-     * <code>null</code> there is no such <code>Manifest</code>.
-     */
-    Manifest getManifest()
-    {
-      return null;
-    }
-
-    Vector getClassPath()
-    {
-      return null;
-    }
-  }
-
-  /**
-   * A <code>Resource</code> represents a resource in some
-   * <code>URLLoader</code>. It also contains all information (e.g.,
-   * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
-   * <code>InputStream</code>) that is necessary for loading resources
-   * and creating classes from a <code>URL</code>.
-   */
-  abstract static class Resource
-  {
-    final URLLoader loader;
-
-    Resource(URLLoader loader)
-    {
-      this.loader = loader;
-    }
-
-    /**
-     * Returns the non-null <code>CodeSource</code> associated with
-     * this resource.
-     */
-    CodeSource getCodeSource()
-    {
-      Certificate[] certs = getCertificates();
-      if (certs == null)
-        return loader.noCertCodeSource;
-      else
-        return new CodeSource(loader.baseURL, certs);
-    }
-
-    /**
-     * Returns <code>Certificates</code> associated with this
-     * resource, or null when there are none.
-     */
-    Certificate[] getCertificates()
-    {
-      return null;
-    }
-
-    /**
-     * Return a <code>URL</code> that can be used to access this resource.
-     */
-    abstract URL getURL();
-
-    /**
-     * Returns the size of this <code>Resource</code> in bytes or
-     * <code>-1</code> when unknown.
-     */
-    abstract int getLength();
-
-    /**
-     * Returns the non-null <code>InputStream</code> through which
-     * this resource can be loaded.
-     */
-    abstract InputStream getInputStream() throws IOException;
-  }
-
-  /**
-   * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
-   * only loading from jar url.
-   */
-  static final class JarURLLoader extends URLLoader
-  {
-    final JarFile jarfile; // The jar file for this url
-    final URL baseJarURL; // Base jar: url for all resources loaded from jar
-
-    Vector classPath;  // The "Class-Path" attribute of this Jar's manifest
-
-    public JarURLLoader(URLClassLoader classloader, URL baseURL,
-                       URL absoluteUrl)
-    {
-      super(classloader, baseURL, absoluteUrl);
-
-      // Cache url prefix for all resources in this jar url.
-      String external = baseURL.toExternalForm();
-      StringBuffer sb = new StringBuffer(external.length() + 6);
-      sb.append("jar:");
-      sb.append(external);
-      sb.append("!/");
-      String jarURL = sb.toString();
-
-      this.classPath = null;
-      URL baseJarURL = null;
-      JarFile jarfile = null;
-      try
-       {
-         baseJarURL =
-           new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
-         
-         jarfile =
-           ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
-          
-         Manifest manifest;
-         Attributes attributes;
-         String classPathString;
-
-          this.classPath = new Vector();
-          
-          ArrayList indexListHeaders = new IndexListParser(jarfile, 
baseJarURL, baseURL).getHeaders();
-          if (indexListHeaders.size() > 0)
-            this.classPath.addAll(indexListHeaders);
-          else if ((manifest = jarfile.getManifest()) != null
-             && (attributes = manifest.getMainAttributes()) != null
-             && ((classPathString 
-                  = attributes.getValue(Attributes.Name.CLASS_PATH)) 
-                 != null))
-           {         
-             StringTokenizer st = new StringTokenizer(classPathString, " ");
-             while (st.hasMoreElements ()) 
-               {  
-                 String e = st.nextToken ();
-                 try
-                   {
-                     this.classPath.add(new URL(baseURL, e));
-                   } 
-                 catch (java.net.MalformedURLException xx)
-                   {
-                     // Give up
-                   }
-               }
-           }
-       }
-      catch (IOException ioe)
-        {
-         /* ignored */
-        }
-
-      this.baseJarURL = baseJarURL;
-      this.jarfile = jarfile;
-    }
-
-    /** get resource with the name "name" in the jar url */
-    Resource getResource(String name)
-    {
-      if (jarfile == null)
-        return null;
-
-      if (name.startsWith("/"))
-        name = name.substring(1);
-
-      JarEntry je = jarfile.getJarEntry(name);
-      if (je != null)
-        return new JarURLResource(this, name, je);
-      else
-        return null;
-    }
-
-    Manifest getManifest()
-    {
-      try
-        {
-          return (jarfile == null) ? null : jarfile.getManifest();
-        }
-      catch (IOException ioe)
-        {
-          return null;
-        }
-    }
-
-    Vector getClassPath()
-    {
-      return classPath;
-    }
-  }
-
-  static final class JarURLResource extends Resource
-  {
-    private final JarEntry entry;
-    private final String name;
-
-    JarURLResource(JarURLLoader loader, String name, JarEntry entry)
-    {
-      super(loader);
-      this.entry = entry;
-      this.name = name;
-    }
-
-    InputStream getInputStream() throws IOException
-    {
-      return ((JarURLLoader) loader).jarfile.getInputStream(entry);
-    }
-
-    int getLength()
-    {
-      return (int) entry.getSize();
-    }
-
-    Certificate[] getCertificates()
-    {
-      // We have to get the entry from the jar file again, because the
-      // certificates will not be available until the entire entry has
-      // been read.
-      return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name))
-        .getCertificates();
-    }
-
-    URL getURL()
-    {
-      try
-        {
-          return new URL(((JarURLLoader) loader).baseJarURL, name,
-                         loader.classloader.getURLStreamHandler("jar"));
-        }
-      catch (MalformedURLException e)
-        {
-          InternalError ie = new InternalError();
-          ie.initCause(e);
-          throw ie;
-        }
-    }
-  }
-
-  /**
-   * Loader for remote directories.
-   */
-  static final class RemoteURLLoader extends URLLoader
-  {
-    private final String protocol;
-
-    RemoteURLLoader(URLClassLoader classloader, URL url)
-    {
-      super(classloader, url);
-      protocol = url.getProtocol();
-    }
-
-    /**
-     * Get a remote resource.
-     * Returns null if no such resource exists.
-     */
-    Resource getResource(String name)
-    {
-      try
-        {
-          URL url =
-            new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
-          URLConnection connection = url.openConnection();
-
-          // Open the connection and check the stream
-          // just to be sure it exists.
-          int length = connection.getContentLength();
-          InputStream stream = connection.getInputStream();
-
-          // We can do some extra checking if it is a http request
-          if (connection instanceof HttpURLConnection)
-            {
-              int response =
-                ((HttpURLConnection) connection).getResponseCode();
-              if (response / 100 != 2)
-                return null;
-            }
-
-          if (stream != null)
-            return new RemoteResource(this, name, url, stream, length);
-          else
-            return null;
-        }
-      catch (IOException ioe)
-        {
-          return null;
-        }
-    }
-  }
-
-  /**
-   * A resource from some remote location.
-   */
-  static final class RemoteResource extends Resource
-  {
-    private final URL url;
-    private final InputStream stream;
-    private final int length;
-
-    RemoteResource(RemoteURLLoader loader, String name, URL url,
-                   InputStream stream, int length)
-    {
-      super(loader);
-      this.url = url;
-      this.stream = stream;
-      this.length = length;
-    }
-
-    InputStream getInputStream() throws IOException
-    {
-      return stream;
-    }
-
-    public int getLength()
-    {
-      return length;
-    }
-
-    public URL getURL()
-    {
-      return url;
-    }
-  }
-
-  /**
-   * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
-   * only loading from file url.
-   */
-  static final class FileURLLoader extends URLLoader
-  {
-    File dir; //the file for this file url
-
-    FileURLLoader(URLClassLoader classloader, URL url, URL absoluteUrl)
-    {
-      super(classloader, url, absoluteUrl);
-      dir = new File(absoluteUrl.getFile());
-    }
-
-    /** get resource with the name "name" in the file url */
-    Resource getResource(String name)
-    {
-      try 
-       {
-          // Make sure that all components in name are valid by walking through
-          // them
-          File file = walkPathComponents(name);
-
-          if (file == null)
-            return null;
-
-          return new FileResource(this, file);
-       }
-      catch (IOException e)
-       {
-         // Fall through...
-       }
-      return null;
-    }
-
-    /**
-     * Walk all path tokens and check them for validity. At no moment, we are
-     * allowed to reach a directory located "above" the root directory, stored
-     * in "dir" property. We are also not allowed to enter a non existing
-     * directory or a non directory component (plain file, symbolic link, ...).
-     * An empty or null path is valid. Pathnames components are separated by
-     * <code>File.separatorChar</code>
-     * 
-     * @param resourceFileName the name to be checked for validity.
-     * @return the canonical file pointed by the resourceFileName or null if 
the
-     *         walking failed
-     * @throws IOException in case of issue when creating the canonical
-     *           resulting file
-     * @see File#separatorChar
-     */
-    private File walkPathComponents(String resourceFileName) throws IOException
-    {
-      StringTokenizer stringTokenizer = new StringTokenizer(resourceFileName, 
File.separator);
-      File currentFile = dir;
-      int tokenCount = stringTokenizer.countTokens();
-
-      for (int i = 0; i < tokenCount - 1; i++)
-        {
-          String currentToken = stringTokenizer.nextToken();
-          
-          // If we are at the root directory and trying to go up, the walking 
is
-          // finished with an error
-          if ("..".equals(currentToken) && currentFile.equals(dir))
-            return null;
-          
-          currentFile = new File(currentFile, currentToken);
-
-          // If the current file doesn't exist or is not a directory, the 
walking is
-          // finished with an error
-          if (! (currentFile.exists() && currentFile.isDirectory()))
-            return null;
-          
-        }
-      
-      // Treat the last token differently, if it exists, because it does not 
need
-      // to be a directory
-      if (tokenCount > 0)
-        {
-          String currentToken = stringTokenizer.nextToken();
-          
-          if ("..".equals(currentToken) && currentFile.equals(dir))
-            return null;
-          
-          currentFile = new File(currentFile, currentToken);
-
-          // If the current file doesn't exist, the walking is
-          // finished with an error
-          if (! currentFile.exists())
-            return null;
-      }
-      
-      return currentFile.getCanonicalFile();
-    }
-  }
-
-  static final class FileResource extends Resource
-  {
-    final File file;
-
-    FileResource(FileURLLoader loader, File file)
-    {
-      super(loader);
-      this.file = file;
-    }
-
-    InputStream getInputStream() throws IOException
-    {
-      return new FileInputStream(file);
-    }
-
-    public int getLength()
-    {
-      return (int) file.length();
-    }
-
-    public URL getURL()
-    {
-      try
-        {
-          return file.toURL();
-        }
-      catch (MalformedURLException e)
-        {
-          InternalError ie = new InternalError();
-          ie.initCause(e);
-          throw ie;
-        }
-    }
-  }
-
-  // Constructors
-
-  /**
    * Creates a URLClassLoader that gets classes from the supplied URLs.
    * To determine if this classloader may be created the constructor of
    * the super class (<code>SecureClassLoader</code>) is called first, which
@@ -753,14 +273,8 @@
     this.factory = factory;
     addURLs(urls);
 
-    // If this factory is still not in factoryCache, add it,
-    //   since we only support three protocols so far, 5 is enough
-    //   for cache initial size
-    synchronized (factoryCache)
-      {
-        if (factory != null && factoryCache.get(factory) == null)
-          factoryCache.put(factory, new HashMap(5));
-      }
+    // If this factory is still not in factoryCache, add it.
+    factoryCache.add(factory);
   }
 
   // Methods
@@ -824,13 +338,57 @@
                absoluteURL = newUrl;
              }
 
-            // Check that it is not a directory
-            if (! (file.endsWith("/") || file.endsWith(File.separator)))
-              loader = new JarURLLoader(this, newUrl, absoluteURL);
-            else if ("file".equals(protocol))
-              loader = new FileURLLoader(this, newUrl, absoluteURL);
-            else
-              loader = new RemoteURLLoader(this, newUrl);
+            // First see if we can find a handler with the correct name.
+            try
+              {
+                Class handler = Class.forName(URL_LOADER_PREFIX + protocol);
+                Class[] argTypes = new Class[] { URLClassLoader.class,
+                                                 URLStreamHandlerCache.class,
+                                                 URLStreamHandlerFactory.class,
+                                                 URL.class,
+                                                 URL.class };
+                Constructor k = handler.getDeclaredConstructor(argTypes);
+                loader
+                  = (URLLoader) k.newInstance(new Object[] { this,
+                                                             factoryCache,
+                                                             factory,
+                                                             newUrl,
+                                                             absoluteURL });
+              }
+            catch (ClassNotFoundException ignore)
+              {
+                // Fall through.
+              }
+            catch (NoSuchMethodException ignore)
+              {
+                // Fall through.
+              }
+            catch (InstantiationException ignore)
+              {
+                // Fall through.
+              }
+            catch (InvocationTargetException ignore)
+              {
+                // Fall through.
+              }
+            catch (IllegalAccessException ignore)
+              {
+                // Fall through.
+              }
+            
+            if (loader == null)
+              {
+                // If it is not a directory, use the jar loader.
+                if (! (file.endsWith("/") || file.endsWith(File.separator)))
+                  loader = new JarURLLoader(this, factoryCache, factory,
+                                            newUrl, absoluteURL);
+                else if ("file".equals(protocol))
+                  loader = new FileURLLoader(this, factoryCache, factory,
+                                             newUrl, absoluteURL);
+                else
+                  loader = new RemoteURLLoader(this, factoryCache, factory,
+                                               newUrl);
+              }
 
             // Cache it.
             urlloaders.put(newUrl, loader);
@@ -966,7 +524,20 @@
   {
     // Just try to find the resource by the (almost) same name
     String resourceName = className.replace('.', '/') + ".class";
-    Resource resource = findURLResource(resourceName);
+    int max = urlinfos.size();
+    Resource resource = null;
+    for (int i = 0; i < max && resource == null; i++)
+      {
+        URLLoader loader = (URLLoader)urlinfos.elementAt(i);
+        if (loader == null)
+          continue;
+
+        Class k = loader.getClass(className);
+        if (k != null)
+          return k;
+
+        resource = loader.getResource(resourceName);
+      }
     if (resource == null)
       throw new ClassNotFoundException(className + " not found in " + this);
 
@@ -1028,12 +599,13 @@
         if (packageName != null && getPackage(packageName) == null)
           {
             // define the package
-            Manifest manifest = resource.loader.getManifest();
+            Manifest manifest = resource.getLoader().getManifest();
             if (manifest == null)
               definePackage(packageName, null, null, null, null, null, null,
                             null);
             else
-              definePackage(packageName, manifest, resource.loader.baseURL);
+              definePackage(packageName, manifest,
+                            resource.getLoader().getBaseURL());
           }
 
         // And finally construct the class!
@@ -1145,34 +717,6 @@
   }
 
   /**
-   * If the URLStreamHandlerFactory has been set this return the appropriate
-   * URLStreamHandler for the given protocol, if not set returns null.
-   *
-   * @param protocol the protocol for which we need a URLStreamHandler
-   * @return the appropriate URLStreamHandler or null
-   */
-  URLStreamHandler getURLStreamHandler(String protocol)
-  {
-    if (factory == null)
-      return null;
-
-    URLStreamHandler handler;
-    synchronized (factoryCache)
-      {
-        // Check if there're handler for the same protocol in cache.
-        HashMap cache = (HashMap) factoryCache.get(factory);
-        handler = (URLStreamHandler) cache.get(protocol);
-        if (handler == null)
-          {
-            // Add it to cache.
-            handler = factory.createURLStreamHandler(protocol);
-            cache.put(protocol, handler);
-          }
-      }
-    return handler;
-  }
-
-  /**
    * Finds all the resources with a particular name from all the locations.
    *
    * @param resourceName the name of the resource to lookup
Index: gnu/java/net/loader/FileResource.java
===================================================================
RCS file: gnu/java/net/loader/FileResource.java
diff -N gnu/java/net/loader/FileResource.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/FileResource.java       1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,82 @@
+/* FileResource.java -- a Resource for file URLs
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public final class FileResource extends Resource
+{
+  final File file;
+
+  public FileResource(FileURLLoader loader, File file)
+  {
+    super(loader);
+    this.file = file;
+  }
+
+  public InputStream getInputStream() throws IOException
+  {
+    return new FileInputStream(file);
+  }
+
+  public int getLength()
+  {
+    return (int) file.length();
+  }
+
+  public URL getURL()
+  {
+    try
+      {
+        return file.toURL();
+      }
+    catch (MalformedURLException e)
+      {
+        InternalError ie = new InternalError();
+        ie.initCause(e);
+        throw ie;
+      }
+  }
+}
Index: gnu/java/net/loader/FileURLLoader.java
===================================================================
RCS file: gnu/java/net/loader/FileURLLoader.java
diff -N gnu/java/net/loader/FileURLLoader.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/FileURLLoader.java      1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,145 @@
+/* FileURLLoader.java -- a URLLoader for file URLs
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.StringTokenizer;
+
+/**
+ * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
+ * only loading from file url.
+ */
+public final class FileURLLoader extends URLLoader
+{
+  File dir; //the file for this file url
+
+  public FileURLLoader(URLClassLoader classloader,
+                       URLStreamHandlerCache cache,
+                       URLStreamHandlerFactory factory,
+                       URL url, URL absoluteUrl)
+  {
+    super(classloader, cache, factory, url, absoluteUrl);
+    dir = new File(absoluteUrl.getFile());
+  }
+
+  /** get resource with the name "name" in the file url */
+  public Resource getResource(String name)
+  {
+    try 
+      {
+        // Make sure that all components in name are valid by walking through
+        // them
+        File file = walkPathComponents(name);
+
+        if (file == null)
+          return null;
+
+        return new FileResource(this, file);
+      }
+    catch (IOException e)
+      {
+        // Fall through...
+      }
+    return null;
+  }
+
+  /**
+   * Walk all path tokens and check them for validity. At no moment, we are
+   * allowed to reach a directory located "above" the root directory, stored
+   * in "dir" property. We are also not allowed to enter a non existing
+   * directory or a non directory component (plain file, symbolic link, ...).
+   * An empty or null path is valid. Pathnames components are separated by
+   * <code>File.separatorChar</code>
+   * 
+   * @param resourceFileName the name to be checked for validity.
+   * @return the canonical file pointed by the resourceFileName or null if the
+   *         walking failed
+   * @throws IOException in case of issue when creating the canonical
+   *           resulting file
+   * @see File#separatorChar
+   */
+  private File walkPathComponents(String resourceFileName) throws IOException
+  {
+    StringTokenizer stringTokenizer = new StringTokenizer(resourceFileName, 
File.separator);
+    File currentFile = dir;
+    int tokenCount = stringTokenizer.countTokens();
+
+    for (int i = 0; i < tokenCount - 1; i++)
+      {
+        String currentToken = stringTokenizer.nextToken();
+        
+        // If we are at the root directory and trying to go up, the walking is
+        // finished with an error
+        if ("..".equals(currentToken) && currentFile.equals(dir))
+          return null;
+        
+        currentFile = new File(currentFile, currentToken);
+
+        // If the current file doesn't exist or is not a directory, the 
walking is
+        // finished with an error
+        if (! (currentFile.exists() && currentFile.isDirectory()))
+          return null;
+        
+      }
+    
+    // Treat the last token differently, if it exists, because it does not need
+    // to be a directory
+    if (tokenCount > 0)
+      {
+        String currentToken = stringTokenizer.nextToken();
+        
+        if ("..".equals(currentToken) && currentFile.equals(dir))
+          return null;
+        
+        currentFile = new File(currentFile, currentToken);
+
+        // If the current file doesn't exist, the walking is
+        // finished with an error
+        if (! currentFile.exists())
+          return null;
+    }
+    
+    return currentFile.getCanonicalFile();
+  }
+}
Index: gnu/java/net/loader/JarURLLoader.java
===================================================================
RCS file: gnu/java/net/loader/JarURLLoader.java
diff -N gnu/java/net/loader/JarURLLoader.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/JarURLLoader.java       1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,124 @@
+package gnu.java.net.loader;
+
+import gnu.java.net.IndexListParser;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+/**
+ * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
+ * only loading from jar url.
+ */
+public final class JarURLLoader extends URLLoader
+{
+  final JarFile jarfile; // The jar file for this url
+  final URL baseJarURL; // Base jar: url for all resources loaded from jar
+
+  Vector classPath;    // The "Class-Path" attribute of this Jar's manifest
+
+  public JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
+                      URLStreamHandlerFactory factory,
+                      URL baseURL, URL absoluteUrl)
+  {
+    super(classloader, cache, factory, baseURL, absoluteUrl);
+
+    // Cache url prefix for all resources in this jar url.
+    String external = baseURL.toExternalForm();
+    StringBuffer sb = new StringBuffer(external.length() + 6);
+    sb.append("jar:");
+    sb.append(external);
+    sb.append("!/");
+    String jarURL = sb.toString();
+
+    this.classPath = null;
+    URL baseJarURL = null;
+    JarFile jarfile = null;
+    try
+      {
+        baseJarURL = new URL(null, jarURL, cache.get(factory, "jar"));
+        
+        jarfile =
+          ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
+        
+        Manifest manifest;
+        Attributes attributes;
+        String classPathString;
+
+        this.classPath = new Vector();
+        
+        ArrayList indexListHeaders = new IndexListParser(jarfile, baseJarURL, 
baseURL).getHeaders();
+        if (indexListHeaders.size() > 0)
+          this.classPath.addAll(indexListHeaders);
+        else if ((manifest = jarfile.getManifest()) != null
+            && (attributes = manifest.getMainAttributes()) != null
+            && ((classPathString 
+          = attributes.getValue(Attributes.Name.CLASS_PATH)) 
+         != null))
+          {          
+            StringTokenizer st = new StringTokenizer(classPathString, " ");
+            while (st.hasMoreElements ()) 
+       {  
+         String e = st.nextToken ();
+         try
+           {
+             this.classPath.add(new URL(baseURL, e));
+           } 
+         catch (java.net.MalformedURLException xx)
+           {
+             // Give up
+           }
+       }
+          }
+      }
+    catch (IOException ioe)
+      {
+        /* ignored */
+      }
+
+    this.baseJarURL = baseJarURL;
+    this.jarfile = jarfile;
+  }
+
+  /** get resource with the name "name" in the jar url */
+  public Resource getResource(String name)
+  {
+    if (jarfile == null)
+      return null;
+
+    if (name.startsWith("/"))
+      name = name.substring(1);
+
+    JarEntry je = jarfile.getJarEntry(name);
+    if (je != null)
+      return new JarURLResource(this, name, je);
+    else
+      return null;
+  }
+
+  public Manifest getManifest()
+  {
+    try
+      {
+        return (jarfile == null) ? null : jarfile.getManifest();
+      }
+    catch (IOException ioe)
+      {
+        return null;
+      }
+  }
+
+  public Vector getClassPath()
+  {
+    return classPath;
+  }
+}
Index: gnu/java/net/loader/JarURLResource.java
===================================================================
RCS file: gnu/java/net/loader/JarURLResource.java
diff -N gnu/java/net/loader/JarURLResource.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/JarURLResource.java     1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,94 @@
+/* JarURLResource.java -- a Resource for jar URLs
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.cert.Certificate;
+import java.util.jar.JarEntry;
+
+public final class JarURLResource extends Resource
+{
+  private final JarEntry entry;
+  private final String name;
+
+  public JarURLResource(JarURLLoader loader, String name, JarEntry entry)
+  {
+    super(loader);
+    this.entry = entry;
+    this.name = name;
+  }
+
+  public InputStream getInputStream() throws IOException
+  {
+    return ((JarURLLoader) loader).jarfile.getInputStream(entry);
+  }
+
+  public int getLength()
+  {
+    return (int) entry.getSize();
+  }
+
+  public Certificate[] getCertificates()
+  {
+    // We have to get the entry from the jar file again, because the
+    // certificates will not be available until the entire entry has
+    // been read.
+    return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name))
+      .getCertificates();
+  }
+
+  public URL getURL()
+  {
+    try
+      {
+        return new URL(((JarURLLoader) loader).baseJarURL, name,
+                       loader.cache.get(loader.factory, "jar"));
+      }
+    catch (MalformedURLException e)
+      {
+        InternalError ie = new InternalError();
+        ie.initCause(e);
+        throw ie;
+      }
+  }
+}
Index: gnu/java/net/loader/RemoteResource.java
===================================================================
RCS file: gnu/java/net/loader/RemoteResource.java
diff -N gnu/java/net/loader/RemoteResource.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/RemoteResource.java     1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,78 @@
+/* Resource.java -- a Resource for "remote" URLs
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * A resource from some remote location.
+ */
+public final class RemoteResource extends Resource
+{
+  private final URL url;
+  private final InputStream stream;
+  final int length;
+
+  public RemoteResource(RemoteURLLoader loader, String name, URL url,
+                        InputStream stream, int length)
+  {
+    super(loader);
+    this.url = url;
+    this.stream = stream;
+    this.length = length;
+  }
+
+  public InputStream getInputStream() throws IOException
+  {
+    return stream;
+  }
+
+  public int getLength()
+  {
+    return length;
+  }
+
+  public URL getURL()
+  {
+    return url;
+  }
+}
Index: gnu/java/net/loader/RemoteURLLoader.java
===================================================================
RCS file: gnu/java/net/loader/RemoteURLLoader.java
diff -N gnu/java/net/loader/RemoteURLLoader.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/RemoteURLLoader.java    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,101 @@
+/* RemoteURLLoader.java -- a URLLoader for "remote" objects
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+import java.net.URLStreamHandlerFactory;
+
+/**
+ * Loader for remote directories.
+ */
+public final class RemoteURLLoader extends URLLoader
+{
+  private final String protocol;
+
+  public RemoteURLLoader(URLClassLoader classloader,
+                         URLStreamHandlerCache cache,
+                         URLStreamHandlerFactory factory,
+                         URL url)
+  {
+    super(classloader, cache, factory, url);
+    protocol = url.getProtocol();
+  }
+
+  /**
+   * Get a remote resource.
+   * Returns null if no such resource exists.
+   */
+  public Resource getResource(String name)
+  {
+    try
+      {
+        URL url = new URL(baseURL, name, cache.get(factory, protocol));
+        URLConnection connection = url.openConnection();
+
+        // Open the connection and check the stream
+        // just to be sure it exists.
+        int length = connection.getContentLength();
+        InputStream stream = connection.getInputStream();
+
+        // We can do some extra checking if it is a http request
+        if (connection instanceof HttpURLConnection)
+          {
+            int response =
+              ((HttpURLConnection) connection).getResponseCode();
+            if (response / 100 != 2)
+              return null;
+          }
+
+        if (stream != null)
+          return new RemoteResource(this, name, url, stream, length);
+        else
+          return null;
+      }
+    catch (IOException ioe)
+      {
+        return null;
+      }
+  }
+}
Index: gnu/java/net/loader/Resource.java
===================================================================
RCS file: gnu/java/net/loader/Resource.java
diff -N gnu/java/net/loader/Resource.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/Resource.java   1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,110 @@
+/* Resource.java -- a resource for URLLoader
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.cert.Certificate;
+
+/**
+ * A <code>Resource</code> represents a resource in some
+ * <code>URLLoader</code>. It also contains all information (e.g.,
+ * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
+ * <code>InputStream</code>) that is necessary for loading resources
+ * and creating classes from a <code>URL</code>.
+ */
+public abstract class Resource
+{
+  final URLLoader loader;
+
+  public Resource(URLLoader loader)
+  {
+    this.loader = loader;
+  }
+
+  /**
+   * Returns the non-null <code>CodeSource</code> associated with
+   * this resource.
+   */
+  public CodeSource getCodeSource()
+  {
+    Certificate[] certs = getCertificates();
+    if (certs == null)
+      return loader.noCertCodeSource;
+    else
+      return new CodeSource(loader.baseURL, certs);
+  }
+
+  /**
+   * Returns <code>Certificates</code> associated with this
+   * resource, or null when there are none.
+   */
+  public Certificate[] getCertificates()
+  {
+    return null;
+  }
+
+  /**
+   * Return the URLLoader for this resource.
+   */
+  public final URLLoader getLoader()
+  {
+    return loader;
+  }
+
+  /**
+   * Return a <code>URL</code> that can be used to access this resource.
+   */
+  public abstract URL getURL();
+
+  /**
+   * Returns the size of this <code>Resource</code> in bytes or
+   * <code>-1</code> when unknown.
+   */
+  public abstract int getLength();
+
+  /**
+   * Returns the non-null <code>InputStream</code> through which
+   * this resource can be loaded.
+   */
+  public abstract InputStream getInputStream() throws IOException;
+}
Index: gnu/java/net/loader/URLLoader.java
===================================================================
RCS file: gnu/java/net/loader/URLLoader.java
diff -N gnu/java/net/loader/URLLoader.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/URLLoader.java  1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,143 @@
+/* URLLoader.java --  base helper class for URLClassLoader
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.security.CodeSource;
+import java.util.Vector;
+import java.util.jar.Manifest;
+
+/**
+ * A <code>URLLoader</code> contains all logic to load resources from a
+ * given base <code>URL</code>.
+ */
+public abstract class URLLoader
+{
+  /**
+   * Our classloader to get info from if needed.
+   */
+  final URLClassLoader classloader;
+
+  /**
+   * The base URL from which all resources are loaded.
+   */
+  final URL baseURL;
+
+  /**
+   * The stream handler factory.
+   */
+  final URLStreamHandlerFactory factory;
+
+  /**
+   * The source for stream handlers.
+   */
+  final URLStreamHandlerCache cache;
+
+  /**
+   * A <code>CodeSource</code> without any associated certificates.
+   * It is common for classes to not have certificates associated
+   * with them.  If they come from the same <code>URLLoader</code>
+   * then it is safe to share the associated <code>CodeSource</code>
+   * between them since <code>CodeSource</code> is immutable.
+   */
+  final CodeSource noCertCodeSource;
+
+  public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
+                   URLStreamHandlerFactory factory,
+                   URL baseURL)
+  {
+    this(classloader, cache, factory, baseURL, baseURL);
+  }
+
+  public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
+                   URLStreamHandlerFactory factory,
+                   URL baseURL, URL overrideURL)
+  {
+    this.classloader = classloader;
+    this.baseURL = baseURL;
+    this.factory = factory;
+    this.cache = cache;
+    this.noCertCodeSource = new CodeSource(overrideURL, null);
+  }
+
+  /**
+   * Return the base URL of this loader.
+   */
+  public final URL getBaseURL()
+  {
+    return baseURL;
+  }
+
+  /**
+   * Returns a <code>Class</code> loaded by this
+   * <code>URLLoader</code>, or <code>null</code> when this loader
+   * either can't load the class or doesn't know how to load classes
+   * at all.  Most subclasses do not need to override this; it is only
+   * useful in situations where the subclass has a more direct way of
+   * making <code>Class</code> objects.
+   */
+  public Class getClass(String className)
+  {
+    return null;
+  }
+
+  /**
+   * Returns a <code>Resource</code> loaded by this
+   * <code>URLLoader</code>, or <code>null</code> when no
+   * <code>Resource</code> with the given name exists.
+   */
+  public abstract Resource getResource(String s);
+
+  /**
+   * Returns the <code>Manifest</code> associated with the
+   * <code>Resource</code>s loaded by this <code>URLLoader</code> or
+   * <code>null</code> there is no such <code>Manifest</code>.
+   */
+  public Manifest getManifest()
+  {
+    return null;
+  }
+
+  public Vector getClassPath()
+  {
+    return null;
+  }
+}
Index: gnu/java/net/loader/URLStreamHandlerCache.java
===================================================================
RCS file: gnu/java/net/loader/URLStreamHandlerCache.java
diff -N gnu/java/net/loader/URLStreamHandlerCache.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/net/loader/URLStreamHandlerCache.java      1 Jan 1970 00:00:00 
-0000
@@ -0,0 +1,84 @@
+/* URLStreamHandlerCache.java -- a cache for URLStreamHandlers
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.loader;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.util.HashMap;
+
+/**
+ */
+public class URLStreamHandlerCache
+{
+  /**
+   * A cache to store mappings between handler factory and its
+   * private protocol handler cache (also a HashMap), so we can avoid
+   * creating handlers each time the same protocol comes.
+   */
+  private HashMap factoryCache = new HashMap(5);
+
+  public URLStreamHandlerCache()
+  {
+  }
+
+  public synchronized void add(URLStreamHandlerFactory factory)
+  {
+    // Since we only support three protocols so far, 5 is enough
+    // for cache initial size.
+    if (factory != null && factoryCache.get(factory) == null)
+      factoryCache.put(factory, new HashMap(5));
+  }
+
+  public synchronized URLStreamHandler get(URLStreamHandlerFactory factory,
+                                           String protocol)
+  {
+    if (factory == null)
+      return null;
+    // Check if there're handler for the same protocol in cache.
+    HashMap cache = (HashMap) factoryCache.get(factory);
+    URLStreamHandler handler = (URLStreamHandler) cache.get(protocol);
+    if (handler == null)
+      {
+        // Add it to cache.
+        handler = factory.createURLStreamHandler(protocol);
+        cache.put(protocol, handler);
+      }
+    return handler;
+  }
+}

Reply via email to