mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1408 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1408 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* URLClassLoader.java --  ClassLoader that loads classes from one or more URLs
 | |
|    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
 | |
|    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 java.net;
 | |
| 
 | |
| 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.security.AccessControlContext;
 | |
| import java.security.AccessController;
 | |
| import java.security.CodeSource;
 | |
| import java.security.PermissionCollection;
 | |
| import java.security.PrivilegedAction;
 | |
| import java.security.SecureClassLoader;
 | |
| import java.security.cert.Certificate;
 | |
| 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;
 | |
| import gnu.gcj.runtime.SharedLibHelper;
 | |
| import gnu.gcj.Core;
 | |
| import gnu.java.net.protocol.core.CoreInputStream;
 | |
| 
 | |
| /**
 | |
|  * A secure class loader that can load classes and resources from
 | |
|  * multiple locations.  Given an array of <code>URL</code>s this class
 | |
|  * loader will retrieve classes and resources by fetching them from
 | |
|  * possible remote locations.  Each <code>URL</code> is searched in
 | |
|  * order in which it was added.  If the file portion of the
 | |
|  * <code>URL</code> ends with a '/' character then it is interpreted
 | |
|  * as a base directory, otherwise it is interpreted as a jar file from
 | |
|  * which the classes/resources are resolved.
 | |
|  *
 | |
|  * <p>New instances can be created by two static
 | |
|  * <code>newInstance()</code> methods or by three public
 | |
|  * contructors. Both ways give the option to supply an initial array
 | |
|  * of <code>URL</code>s and (optionally) a parent classloader (that is
 | |
|  * different from the standard system class loader).</p>
 | |
|  *
 | |
|  * <p>Normally creating a <code>URLClassLoader</code> throws a
 | |
|  * <code>SecurityException</code> if a <code>SecurityManager</code> is
 | |
|  * installed and the <code>checkCreateClassLoader()</code> method does
 | |
|  * not return true.  But the <code>newInstance()</code> methods may be
 | |
|  * used by any code as long as it has permission to acces the given
 | |
|  * <code>URL</code>s.  <code>URLClassLoaders</code> created by the
 | |
|  * <code>newInstance()</code> methods also explicitly call the
 | |
|  * <code>checkPackageAccess()</code> method of
 | |
|  * <code>SecurityManager</code> if one is installed before trying to
 | |
|  * load a class.  Note that only subclasses of
 | |
|  * <code>URLClassLoader</code> can add new URLs after the
 | |
|  * URLClassLoader had been created. But it is always possible to get
 | |
|  * an array of all URLs that the class loader uses to resolve classes
 | |
|  * and resources by way of the <code>getURLs()</code> method.</p>
 | |
|  *
 | |
|  * <p>Open issues:
 | |
|  * <ul>
 | |
|  *
 | |
|  * <li>Should the URLClassLoader actually add the locations found in
 | |
|  * the manifest or is this the responsibility of some other
 | |
|  * loader/(sub)class?  (see <a
 | |
|  * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
 | |
|  * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
 | |
|  *
 | |
|  * <li>How does <code>definePackage()</code> and sealing work
 | |
|  * precisely?</li>
 | |
|  *
 | |
|  * <li>We save and use the security context (when a created by
 | |
|  * <code>newInstance()</code> but do we have to use it in more
 | |
|  * places?</li>
 | |
|  *
 | |
|  * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
 | |
|  *
 | |
|  * </ul>
 | |
|  * </p>
 | |
|  *
 | |
|  * @since 1.2
 | |
|  *
 | |
|  * @author Mark Wielaard (mark@klomp.org)
 | |
|  * @author Wu Gansha (gansha.wu@intel.com)
 | |
|  */
 | |
| public class URLClassLoader extends SecureClassLoader
 | |
| {
 | |
|   // Class Variables
 | |
| 
 | |
|   /**
 | |
|    * A global cache to store mappings between URLLoader and URL,
 | |
|    * so we can avoid do all the homework each time the same URL
 | |
|    * comes.
 | |
|    * XXX - Keeps these loaders forever which prevents garbage collection.
 | |
|    */
 | |
|   private static HashMap urlloaders = new HashMap();
 | |
| 
 | |
|   /**
 | |
|    * 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.
 | |
|    */
 | |
|   private static HashMap factoryCache = new HashMap(5);
 | |
| 
 | |
|   // Instance variables
 | |
| 
 | |
|   /** Locations to load classes from */
 | |
|   private final Vector urls = new Vector();
 | |
| 
 | |
|   /**
 | |
|    * Store pre-parsed information for each url into this vector: each
 | |
|    * element is a URL loader.  A jar file has its own class-path
 | |
|    * attribute which adds to the URLs that will be searched, but this
 | |
|    * does not add to the list of urls.
 | |
|    */
 | |
|   private final Vector urlinfos = new Vector();
 | |
| 
 | |
|   /** Factory used to get the protocol handlers of the URLs */
 | |
|   private final URLStreamHandlerFactory factory;
 | |
| 
 | |
|   /**
 | |
|    * The security context when created from <code>newInstance()</code>
 | |
|    * or null when created through a normal constructor or when no
 | |
|    * <code>SecurityManager</code> was installed.
 | |
|    */
 | |
|   private final AccessControlContext securityContext;
 | |
| 
 | |
|   // 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>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.
 | |
|      */
 | |
|     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.
 | |
|      */
 | |
|     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;
 | |
|     final String name;
 | |
| 
 | |
|     Resource(URLLoader loader, String name)
 | |
|     {
 | |
|       this.loader = loader;
 | |
|       this.name = name;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       super(classloader, baseURL);
 | |
| 
 | |
|       // 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;
 | |
| 
 | |
| 	  if ((manifest = jarfile.getManifest()) != null
 | |
| 	      && (attributes = manifest.getMainAttributes()) != null
 | |
| 	      && ((classPathString 
 | |
| 		   = attributes.getValue(Attributes.Name.CLASS_PATH)) 
 | |
| 		  != null))
 | |
| 	    {
 | |
| 	      this.classPath = new Vector();
 | |
| 	      
 | |
| 	      StringTokenizer st = new StringTokenizer(classPathString, " ");
 | |
| 	      while (st.hasMoreElements ()) 
 | |
| 		{  
 | |
| 		  String e = st.nextToken ();
 | |
| 		  try
 | |
| 		    {
 | |
| 		      URL url = new URL(baseURL, e);
 | |
| 		      this.classPath.add(url);
 | |
| 		    } 
 | |
| 		  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;
 | |
| 
 | |
|     JarURLResource(JarURLLoader loader, String name, JarEntry entry)
 | |
|     {
 | |
|       super(loader, name);
 | |
|       this.entry = entry;
 | |
|     }
 | |
| 
 | |
|     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, name);
 | |
|       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>SoURLLoader</code> is a type of <code>URLLoader</code>
 | |
|    * that loads classes and resources from a shared library.
 | |
|    */
 | |
|   final static class SoURLLoader extends URLLoader
 | |
|   {
 | |
|     SharedLibHelper helper;
 | |
| 
 | |
|     SoURLLoader(URLClassLoader classloader, URL url)
 | |
|     {
 | |
|       this(classloader, url, url);
 | |
|     }
 | |
| 
 | |
|     SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL)
 | |
|     {
 | |
|       super(classloader, url, overrideURL);
 | |
|       helper = SharedLibHelper.findHelper(classloader, url.getFile(),
 | |
| 					  noCertCodeSource, true);
 | |
|     }
 | |
| 
 | |
|     Class getClass(String className)
 | |
|     {
 | |
|       return helper.findClass(className);
 | |
|     }
 | |
| 
 | |
|     Resource getResource(String name)
 | |
|     {
 | |
|       URL url = helper.findResource(name);
 | |
|       if (url == null)
 | |
| 	return null;
 | |
|       return new SoResource(this, name, url);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   final static class SoResource extends Resource
 | |
|   {
 | |
|     SoResource(SoURLLoader loader, String name, URL url)
 | |
|     {
 | |
|       super(loader, name);
 | |
|       this.url = url;
 | |
|     }
 | |
| 
 | |
|     InputStream getInputStream() throws IOException
 | |
|     {
 | |
|       URLConnection conn = url.openConnection();
 | |
|       return conn.getInputStream();
 | |
|     }
 | |
| 
 | |
|     public int getLength()
 | |
|     {
 | |
|       // FIXME we could find this by asking the core object.
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     public URL getURL ()
 | |
|     {
 | |
|       return url;
 | |
|     }
 | |
| 
 | |
|     final URL 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)
 | |
|     {
 | |
|       super(classloader, url);
 | |
|       dir = new File(baseURL.getFile());
 | |
|     }
 | |
| 
 | |
|     /** get resource with the name "name" in the file url */
 | |
|     Resource getResource(String name)
 | |
|     {
 | |
|       try 
 | |
|  	{
 | |
|  	  File file = new File(dir, name).getCanonicalFile();
 | |
|  	  if (file.exists() && !file.isDirectory())
 | |
|  	    return new FileResource(this, file.getPath(), file);
 | |
|  	}
 | |
|       catch (IOException e)
 | |
|  	{
 | |
|  	  // Fall through...
 | |
|  	}
 | |
|       return null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static final class FileResource extends Resource
 | |
|   {
 | |
|     final File file;
 | |
| 
 | |
|     FileResource(FileURLLoader loader, String name, File file)
 | |
|     {
 | |
|       super(loader, name);
 | |
|       this.file = file;
 | |
|     }
 | |
| 
 | |
|     InputStream getInputStream() throws IOException
 | |
|     {
 | |
|       // Delegate to the URL content handler mechanism to retrieve an
 | |
|       // HTML representation of the directory listing if a directory
 | |
|       if (file.isDirectory())
 | |
|         {
 | |
|           URL url = getURL();
 | |
|           return url.openStream();
 | |
|         }
 | |
|       // Otherwise simply return a FileInputStream
 | |
|       return new FileInputStream(file);
 | |
|     }
 | |
| 
 | |
|     public int getLength()
 | |
|     {
 | |
|       // Delegate to the URL content handler mechanism to retrieve the
 | |
|       // length of the HTML representation of the directory listing if
 | |
|       // a directory, or -1 if an exception occurs opening the directory.
 | |
|       if (file.isDirectory())
 | |
|         {
 | |
|           URL url = getURL();
 | |
|           try
 | |
|             {
 | |
|               URLConnection connection = url.openConnection();
 | |
|               return connection.getContentLength();
 | |
|             }
 | |
|           catch (IOException e)
 | |
|             {
 | |
|               return -1;
 | |
|             }
 | |
|         }
 | |
|       // Otherwise simply return the file length
 | |
|       return (int) file.length();
 | |
|     }
 | |
| 
 | |
|     public URL getURL()
 | |
|     {
 | |
|       try
 | |
|         {
 | |
|           return new URL(loader.baseURL, name,
 | |
|                          loader.classloader.getURLStreamHandler("file"));
 | |
|         }
 | |
|       catch (MalformedURLException e)
 | |
|         {
 | |
|           InternalError ie = new InternalError();
 | |
|           ie.initCause(e);
 | |
|           throw ie;
 | |
|         }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A <code>CoreURLLoader</code> is a type of <code>URLLoader</code>
 | |
|    * only loading from core url.
 | |
|    */
 | |
|   static final class CoreURLLoader extends URLLoader
 | |
|   {
 | |
|     private String dir;
 | |
| 
 | |
|     CoreURLLoader(URLClassLoader classloader, URL url)
 | |
|     {
 | |
|       super(classloader, url);
 | |
|       dir = baseURL.getFile();
 | |
|     }
 | |
| 
 | |
|     /** get resource with the name "name" in the core url */
 | |
|     Resource getResource(String name)
 | |
|     {
 | |
|       Core core = Core.find (dir + name);
 | |
|       if (core != null)
 | |
|         return new CoreResource(this, name, core);
 | |
|       return null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static final class CoreResource extends Resource
 | |
|   {
 | |
|     final Core core;
 | |
| 
 | |
|     CoreResource(CoreURLLoader loader, String name, Core core)
 | |
|     {
 | |
|       super(loader, name);
 | |
|       this.core = core;
 | |
|     }
 | |
| 
 | |
|     InputStream getInputStream() throws IOException
 | |
|     {
 | |
|       return new CoreInputStream(core);
 | |
|     }
 | |
| 
 | |
|     public int getLength()
 | |
|     {
 | |
|       return core.length;
 | |
|     }
 | |
| 
 | |
|     public URL getURL()
 | |
|     {
 | |
|       try
 | |
|         {
 | |
|           return new URL(loader.baseURL, name,
 | |
|                          loader.classloader.getURLStreamHandler("core"));
 | |
|         }
 | |
|       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
 | |
|    * can throw a SecurityException. Then the supplied URLs are added
 | |
|    * in the order given to the URLClassLoader which uses these URLs to
 | |
|    * load classes and resources (after using the default parent ClassLoader).
 | |
|    *
 | |
|    * @exception SecurityException if the SecurityManager disallows the
 | |
|    * creation of a ClassLoader.
 | |
|    * @param urls Locations that should be searched by this ClassLoader when
 | |
|    * resolving Classes or Resources.
 | |
|    * @see SecureClassLoader
 | |
|    */
 | |
|   public URLClassLoader(URL[] urls) throws SecurityException
 | |
|   {
 | |
|     super();
 | |
|     this.factory = null;
 | |
|     this.securityContext = null;
 | |
|     addURLs(urls);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Private constructor used by the static
 | |
|    * <code>newInstance(URL[])</code> method.  Creates an
 | |
|    * <code>URLClassLoader</code> without any <code>URL</code>s
 | |
|    * yet. This is used to bypass the normal security check for
 | |
|    * creating classloaders, but remembers the security context which
 | |
|    * will be used when defining classes.  The <code>URL</code>s to
 | |
|    * load from must be added by the <code>newInstance()</code> method
 | |
|    * in the security context of the caller.
 | |
|    *
 | |
|    * @param securityContext the security context of the unprivileged code.
 | |
|    */
 | |
|   private URLClassLoader(AccessControlContext securityContext)
 | |
|   {
 | |
|     super();
 | |
|     this.factory = null;
 | |
|     this.securityContext = securityContext;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>URLClassLoader</code> that gets classes from the supplied
 | |
|    * <code>URL</code>s.
 | |
|    * To determine if this classloader may be created the constructor of
 | |
|    * the super class (<code>SecureClassLoader</code>) is called first, which
 | |
|    * can throw a SecurityException. Then the supplied URLs are added
 | |
|    * in the order given to the URLClassLoader which uses these URLs to
 | |
|    * load classes and resources (after using the supplied parent ClassLoader).
 | |
|    * @exception SecurityException if the SecurityManager disallows the
 | |
|    * creation of a ClassLoader.
 | |
|    * @exception SecurityException
 | |
|    * @param urls Locations that should be searched by this ClassLoader when
 | |
|    * resolving Classes or Resources.
 | |
|    * @param parent The parent class loader used before trying this class
 | |
|    * loader.
 | |
|    * @see SecureClassLoader
 | |
|    */
 | |
|   public URLClassLoader(URL[] urls, ClassLoader parent)
 | |
|     throws SecurityException
 | |
|   {
 | |
|     super(parent);
 | |
|     this.factory = null;
 | |
|     this.securityContext = null;
 | |
|     addURLs(urls);
 | |
|   }
 | |
| 
 | |
|   // Package-private to avoid a trampoline constructor.
 | |
|   /**
 | |
|    * Package-private constructor used by the static
 | |
|    * <code>newInstance(URL[])</code> method.  Creates an
 | |
|    * <code>URLClassLoader</code> with the given parent but without any
 | |
|    * <code>URL</code>s yet. This is used to bypass the normal security
 | |
|    * check for creating classloaders, but remembers the security
 | |
|    * context which will be used when defining classes.  The
 | |
|    * <code>URL</code>s to load from must be added by the
 | |
|    * <code>newInstance()</code> method in the security context of the
 | |
|    * caller.
 | |
|    *
 | |
|    * @param securityContext the security context of the unprivileged code.
 | |
|    */
 | |
|   URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
 | |
|   {
 | |
|     super(parent);
 | |
|     this.factory = null;
 | |
|     this.securityContext = securityContext;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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
 | |
|    * can throw a SecurityException. Then the supplied URLs are added
 | |
|    * in the order given to the URLClassLoader which uses these URLs to
 | |
|    * load classes and resources (after using the supplied parent ClassLoader).
 | |
|    * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
 | |
|    * protocol handlers of the supplied URLs.
 | |
|    * @exception SecurityException if the SecurityManager disallows the
 | |
|    * creation of a ClassLoader.
 | |
|    * @exception SecurityException
 | |
|    * @param urls Locations that should be searched by this ClassLoader when
 | |
|    * resolving Classes or Resources.
 | |
|    * @param parent The parent class loader used before trying this class
 | |
|    * loader.
 | |
|    * @param factory Used to get the protocol handler for the URLs.
 | |
|    * @see SecureClassLoader
 | |
|    */
 | |
|   public URLClassLoader(URL[] urls, ClassLoader parent,
 | |
|                         URLStreamHandlerFactory factory)
 | |
|     throws SecurityException
 | |
|   {
 | |
|     super(parent);
 | |
|     this.securityContext = null;
 | |
|     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));
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   // Methods
 | |
| 
 | |
|   /**
 | |
|    * Adds a new location to the end of the internal URL store.
 | |
|    * @param newUrl the location to add
 | |
|    */
 | |
|   protected void addURL(URL newUrl)
 | |
|   {
 | |
|     urls.add(newUrl);
 | |
|     addURLImpl(newUrl);
 | |
|   }
 | |
| 
 | |
|   private void addURLImpl(URL newUrl)
 | |
|   {
 | |
|     synchronized (this)
 | |
|       {
 | |
|         if (newUrl == null)
 | |
|           return; // Silently ignore...
 | |
| 
 | |
| 	// Reset the toString() value.
 | |
| 	thisString = null;
 | |
| 
 | |
|         // Check global cache to see if there're already url loader
 | |
|         // for this url.
 | |
|         URLLoader loader = (URLLoader) urlloaders.get(newUrl);
 | |
|         if (loader == null)
 | |
|           {
 | |
|             String file = newUrl.getFile();
 | |
|             String protocol = newUrl.getProtocol();
 | |
| 
 | |
|             // Check that it is not a directory
 | |
| 	    if ("gcjlib".equals(protocol))
 | |
| 	      loader = new SoURLLoader(this, newUrl);
 | |
| 	    else if (! (file.endsWith("/") || file.endsWith(File.separator)))
 | |
|               loader = new JarURLLoader(this, newUrl);
 | |
|             else if ("file".equals(protocol))
 | |
|               loader = new FileURLLoader(this, newUrl);
 | |
| 	    else if ("core".equals(protocol))
 | |
| 	      loader = new CoreURLLoader(this, newUrl);
 | |
|             else
 | |
|               loader = new RemoteURLLoader(this, newUrl);
 | |
| 
 | |
|             // Cache it.
 | |
|             urlloaders.put(newUrl, loader);
 | |
|           }
 | |
| 
 | |
| 	urlinfos.add(loader);
 | |
| 
 | |
| 	Vector extraUrls = loader.getClassPath();
 | |
| 	if (extraUrls != null)
 | |
| 	  {
 | |
| 	    Iterator it = extraUrls.iterator();
 | |
| 	    while (it.hasNext())
 | |
| 	      {
 | |
| 		URL url = (URL)it.next();
 | |
| 		URLLoader extraLoader = (URLLoader) urlloaders.get(url);
 | |
| 		if (! urlinfos.contains (extraLoader))
 | |
| 		  addURLImpl(url);
 | |
| 	      }
 | |
| 	  }
 | |
| 
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Adds an array of new locations to the end of the internal URL store.
 | |
|    * @param newUrls the locations to add
 | |
|    */
 | |
|   private void addURLs(URL[] newUrls)
 | |
|   {
 | |
|     for (int i = 0; i < newUrls.length; i++)
 | |
|       addURL(newUrls[i]);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Look in both Attributes for a given value.  The first Attributes
 | |
|    * object, if not null, has precedence.
 | |
|    */
 | |
|   private String getAttributeValue(Attributes.Name name, Attributes first,
 | |
| 				   Attributes second)
 | |
|   {
 | |
|     String result = null;
 | |
|     if (first != null)
 | |
|       result = first.getValue(name);
 | |
|     if (result == null)
 | |
|       result = second.getValue(name);
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Defines a Package based on the given name and the supplied manifest
 | |
|    * information. The manifest indicates the title, version and
 | |
|    * vendor information of the specification and implementation and whether the
 | |
|    * package is sealed. If the Manifest indicates that the package is sealed
 | |
|    * then the Package will be sealed with respect to the supplied URL.
 | |
|    *
 | |
|    * @exception IllegalArgumentException If this package name already exists
 | |
|    * in this class loader
 | |
|    * @param name The name of the package
 | |
|    * @param manifest The manifest describing the specification,
 | |
|    * implementation and sealing details of the package
 | |
|    * @param url the code source url to seal the package
 | |
|    * @return the defined Package
 | |
|    */
 | |
|   protected Package definePackage(String name, Manifest manifest, URL url)
 | |
|     throws IllegalArgumentException
 | |
|   {
 | |
|     // Compute the name of the package as it may appear in the
 | |
|     // Manifest.
 | |
|     StringBuffer xform = new StringBuffer(name);
 | |
|     for (int i = xform.length () - 1; i >= 0; --i)
 | |
|       if (xform.charAt(i) == '.')
 | |
| 	xform.setCharAt(i, '/');
 | |
|     xform.append('/');
 | |
|     String xformName = xform.toString();
 | |
| 
 | |
|     Attributes entryAttr = manifest.getAttributes(xformName);
 | |
|     Attributes attr = manifest.getMainAttributes();
 | |
| 
 | |
|     String specTitle
 | |
|       = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE,
 | |
| 			  entryAttr, attr);
 | |
|     String specVersion
 | |
|       = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION,
 | |
| 			  entryAttr, attr);
 | |
|     String specVendor
 | |
|       = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR,
 | |
| 			  entryAttr, attr);
 | |
|     String implTitle
 | |
|       = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE,
 | |
| 			  entryAttr, attr);
 | |
|     String implVersion
 | |
|       = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION,
 | |
| 			  entryAttr, attr);
 | |
|     String implVendor
 | |
|       = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR,
 | |
| 			  entryAttr, attr);
 | |
| 
 | |
|     // Look if the Manifest indicates that this package is sealed
 | |
|     // XXX - most likely not completely correct!
 | |
|     // Shouldn't we also check the sealed attribute of the complete jar?
 | |
|     // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
 | |
|     // But how do we get that jar manifest here?
 | |
|     String sealed = attr.getValue(Attributes.Name.SEALED);
 | |
|     if ("false".equals(sealed))
 | |
|       // make sure that the URL is null so the package is not sealed
 | |
|       url = null;
 | |
| 
 | |
|     return definePackage(name,
 | |
| 			 specTitle, specVendor, specVersion,
 | |
| 			 implTitle, implVendor, implVersion,
 | |
| 			 url);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Finds (the first) class by name from one of the locations. The locations
 | |
|    * are searched in the order they were added to the URLClassLoader.
 | |
|    *
 | |
|    * @param className the classname to find
 | |
|    * @exception ClassNotFoundException when the class could not be found or
 | |
|    * loaded
 | |
|    * @return a Class object representing the found class
 | |
|    */
 | |
|   protected Class findClass(final String className)
 | |
|     throws ClassNotFoundException
 | |
|   {
 | |
|     // Just try to find the resource by the (almost) same name
 | |
|     String resourceName = className.replace('.', '/') + ".class";
 | |
|     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);
 | |
| 
 | |
|     // Try to read the class data, create the CodeSource, Package and
 | |
|     // construct the class (and watch out for those nasty IOExceptions)
 | |
|     try
 | |
|       {
 | |
|         byte[] data;
 | |
|         InputStream in = resource.getInputStream();
 | |
| 	int length = resource.getLength();
 | |
| 	if (length != -1)
 | |
| 	  {
 | |
| 	    // We know the length of the data.
 | |
| 	    // Just try to read it in all at once
 | |
| 	    data = new byte[length];
 | |
| 	    int pos = 0;
 | |
| 	    while (length - pos > 0)
 | |
| 	      {
 | |
| 		int len = in.read(data, pos, length - pos);
 | |
| 		if (len == -1)
 | |
| 		  throw new EOFException("Not enough data reading from: "
 | |
| 					 + in);
 | |
| 		pos += len;
 | |
| 	      }
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    // We don't know the data length.
 | |
| 	    // Have to read it in chunks.
 | |
| 	    ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
 | |
| 	    byte[] b = new byte[4096];
 | |
| 	    int l = 0;
 | |
| 	    while (l != -1)
 | |
| 	      {
 | |
| 		l = in.read(b);
 | |
| 		if (l != -1)
 | |
| 		  out.write(b, 0, l);
 | |
| 	      }
 | |
| 	    data = out.toByteArray();
 | |
|           }
 | |
|         final byte[] classData = data;
 | |
| 
 | |
|         // Now get the CodeSource
 | |
|         final CodeSource source = resource.getCodeSource();
 | |
| 
 | |
|         // Find out package name
 | |
|         String packageName = null;
 | |
|         int lastDot = className.lastIndexOf('.');
 | |
|         if (lastDot != -1)
 | |
|           packageName = className.substring(0, lastDot);
 | |
| 
 | |
|         if (packageName != null && getPackage(packageName) == null)
 | |
|           {
 | |
|             // define the package
 | |
|             Manifest manifest = resource.loader.getManifest();
 | |
|             if (manifest == null)
 | |
|               definePackage(packageName, null, null, null, null, null, null,
 | |
|                             null);
 | |
|             else
 | |
|               definePackage(packageName, manifest, resource.loader.baseURL);
 | |
|           }
 | |
| 
 | |
|         // And finally construct the class!
 | |
|         SecurityManager sm = System.getSecurityManager();
 | |
|         Class result = null;
 | |
|         if (sm != null && securityContext != null)
 | |
|           {
 | |
|             result = (Class)AccessController.doPrivileged
 | |
|               (new PrivilegedAction()
 | |
|                 {
 | |
|                   public Object run()
 | |
|                   {
 | |
|                     return defineClass(className, classData,
 | |
|                                        0, classData.length,
 | |
|                                        source);
 | |
|                   }
 | |
|                 }, securityContext);
 | |
|           }
 | |
|         else
 | |
|           result = defineClass(className, classData, 0, classData.length, source);
 | |
| 
 | |
|         super.setSigners(result, resource.getCertificates());
 | |
|         return result;
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
| 	ClassNotFoundException cnfe;
 | |
| 	cnfe = new ClassNotFoundException(className + " not found in " + this);
 | |
| 	cnfe.initCause(ioe);
 | |
| 	throw cnfe;
 | |
|       }
 | |
|   }
 | |
|   
 | |
|   // Cached String representation of this URLClassLoader
 | |
|   private String thisString;
 | |
|   
 | |
|   /**
 | |
|    * Returns a String representation of this URLClassLoader giving the
 | |
|    * actual Class name, the URLs that are searched and the parent
 | |
|    * ClassLoader.
 | |
|    */
 | |
|   public String toString()
 | |
|   {
 | |
|     synchronized (this)
 | |
|       {
 | |
| 	if (thisString == null)
 | |
| 	  {
 | |
| 	    StringBuffer sb = new StringBuffer();
 | |
| 	    sb.append(this.getClass().getName());
 | |
| 	    sb.append("{urls=[" );
 | |
| 	    URL[] thisURLs = getURLs();
 | |
| 	    for (int i = 0; i < thisURLs.length; i++)
 | |
| 	      {
 | |
| 		sb.append(thisURLs[i]);
 | |
| 		if (i < thisURLs.length - 1)
 | |
| 		  sb.append(',');
 | |
| 	      }
 | |
| 	    sb.append(']');
 | |
| 	    sb.append(", parent=");
 | |
| 	    sb.append(getParent());
 | |
| 	    sb.append('}');
 | |
| 	    thisString = sb.toString();
 | |
| 	  }
 | |
| 	return thisString;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Finds the first occurrence of a resource that can be found. The locations
 | |
|    * are searched in the order they were added to the URLClassLoader.
 | |
|    *
 | |
|    * @param resourceName the resource name to look for
 | |
|    * @return the URLResource for the resource if found, null otherwise
 | |
|    */
 | |
|   private Resource findURLResource(String resourceName)
 | |
|   {
 | |
|     int max = urlinfos.size();
 | |
|     for (int i = 0; i < max; i++)
 | |
|       {
 | |
|         URLLoader loader = (URLLoader) urlinfos.elementAt(i);
 | |
|         if (loader == null)
 | |
|           continue;
 | |
| 
 | |
|         Resource resource = loader.getResource(resourceName);
 | |
|         if (resource != null)
 | |
|           return resource;
 | |
|       }
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Finds the first occurrence of a resource that can be found.
 | |
|    *
 | |
|    * @param resourceName the resource name to look for
 | |
|    * @return the URL if found, null otherwise
 | |
|    */
 | |
|   public URL findResource(String resourceName)
 | |
|   {
 | |
|     Resource resource = findURLResource(resourceName);
 | |
|     if (resource != null)
 | |
|       return resource.getURL();
 | |
| 
 | |
|     // Resource not found
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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.
 | |
|    *
 | |
|    * @exception IOException when an error occurs accessing one of the
 | |
|    * locations
 | |
|    * @param resourceName the name of the resource to lookup
 | |
|    * @return a (possible empty) enumeration of URLs where the resource can be
 | |
|    * found
 | |
|    */
 | |
|   public Enumeration findResources(String resourceName)
 | |
|     throws IOException
 | |
|   {
 | |
|     Vector resources = new Vector();
 | |
|     int max = urlinfos.size();
 | |
|     for (int i = 0; i < max; i++)
 | |
|       {
 | |
|         URLLoader loader = (URLLoader) urlinfos.elementAt(i);
 | |
|         Resource resource = loader.getResource(resourceName);
 | |
|         if (resource != null)
 | |
|           resources.add(resource.getURL());
 | |
|       }
 | |
|     return resources.elements();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the permissions needed to access a particular code
 | |
|    * source.  These permissions includes those returned by
 | |
|    * <code>SecureClassLoader.getPermissions()</code> and the actual
 | |
|    * permissions to access the objects referenced by the URL of the
 | |
|    * code source.  The extra permissions added depend on the protocol
 | |
|    * and file portion of the URL in the code source. If the URL has
 | |
|    * the "file" protocol ends with a '/' character then it must be a
 | |
|    * directory and a file Permission to read everything in that
 | |
|    * directory and all subdirectories is added. If the URL had the
 | |
|    * "file" protocol and doesn't end with a '/' character then it must
 | |
|    * be a normal file and a file permission to read that file is
 | |
|    * added. If the <code>URL</code> has any other protocol then a
 | |
|    * socket permission to connect and accept connections from the host
 | |
|    * portion of the URL is added.
 | |
|    *
 | |
|    * @param source The codesource that needs the permissions to be accessed
 | |
|    * @return the collection of permissions needed to access the code resource
 | |
|    * @see java.security.SecureClassLoader#getPermissions()
 | |
|    */
 | |
|   protected PermissionCollection getPermissions(CodeSource source)
 | |
|   {
 | |
|     // XXX - This implementation does exactly as the Javadoc describes.
 | |
|     // But maybe we should/could use URLConnection.getPermissions()?
 | |
|     // First get the permissions that would normally be granted
 | |
|     PermissionCollection permissions = super.getPermissions(source);
 | |
| 
 | |
|     // Now add any extra permissions depending on the URL location.
 | |
|     URL url = source.getLocation();
 | |
|     String protocol = url.getProtocol();
 | |
|     if (protocol.equals("file"))
 | |
|       {
 | |
|         String file = url.getFile();
 | |
| 
 | |
|         // If the file end in / it must be an directory.
 | |
|         if (file.endsWith("/") || file.endsWith(File.separator))
 | |
|           {
 | |
|             // Grant permission to read everything in that directory and
 | |
|             // all subdirectories.
 | |
|             permissions.add(new FilePermission(file + "-", "read"));
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             // It is a 'normal' file.
 | |
|             // Grant permission to access that file.
 | |
|             permissions.add(new FilePermission(file, "read"));
 | |
|           }
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         // Grant permission to connect to and accept connections from host
 | |
|         String host = url.getHost();
 | |
|         if (host != null)
 | |
|           permissions.add(new SocketPermission(host, "connect,accept"));
 | |
|       }
 | |
| 
 | |
|     return permissions;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns all the locations that this class loader currently uses the
 | |
|    * resolve classes and resource. This includes both the initially supplied
 | |
|    * URLs as any URLs added later by the loader.
 | |
|    * @return All the currently used URLs
 | |
|    */
 | |
|   public URL[] getURLs()
 | |
|   {
 | |
|     return (URL[]) urls.toArray(new URL[urls.size()]);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new instance of a <code>URLClassLoader</code> that gets
 | |
|    * classes from the supplied <code>URL</code>s. This class loader
 | |
|    * will have as parent the standard system class loader.
 | |
|    *
 | |
|    * @param urls the initial URLs used to resolve classes and
 | |
|    * resources
 | |
|    *
 | |
|    * @return the class loader
 | |
|    *
 | |
|    * @exception SecurityException when the calling code does not have
 | |
|    * permission to access the given <code>URL</code>s
 | |
|    */
 | |
|   public static URLClassLoader newInstance(URL[] urls)
 | |
|     throws SecurityException
 | |
|   {
 | |
|     return newInstance(urls, null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new instance of a <code>URLClassLoader</code> that gets
 | |
|    * classes from the supplied <code>URL</code>s and with the supplied
 | |
|    * loader as parent class loader.
 | |
|    *
 | |
|    * @param urls the initial URLs used to resolve classes and
 | |
|    * resources
 | |
|    * @param parent the parent class loader
 | |
|    *
 | |
|    * @return the class loader
 | |
|    *
 | |
|    * @exception SecurityException when the calling code does not have
 | |
|    * permission to access the given <code>URL</code>s
 | |
|    */
 | |
|   public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
 | |
|     throws SecurityException
 | |
|   {
 | |
|     SecurityManager sm = System.getSecurityManager();
 | |
|     if (sm == null)
 | |
|       return new URLClassLoader(urls, parent);
 | |
|     else
 | |
|       {
 | |
|         final Object securityContext = sm.getSecurityContext();
 | |
| 
 | |
|         // XXX - What to do with anything else then an AccessControlContext?
 | |
|         if (! (securityContext instanceof AccessControlContext))
 | |
|           throw new SecurityException("securityContext must be AccessControlContext: "
 | |
|                                       + securityContext);
 | |
| 
 | |
|         URLClassLoader loader =
 | |
|           (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
 | |
|               {
 | |
|                 public Object run()
 | |
|                 {
 | |
|                   return new URLClassLoader(parent,
 | |
|                                             (AccessControlContext) securityContext);
 | |
|                 }
 | |
|               });
 | |
|         loader.addURLs(urls);
 | |
|         return loader;
 | |
|       }
 | |
|   }
 | |
| }
 |