Ignore:
Timestamp:
Apr 27, 2004, 8:39:34 PM (22 years ago)
Author:
bird
Message:

GCC v3.3.3 sources.

Location:
branches/GNU/src/gcc
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/GNU/src/gcc

    • Property svn:ignore
      •  

        old new  
        2626configure.vr
        2727configure.vrs
         28
        2829Makefile
        29 dir.info
        3030lost+found
        3131update.out
  • branches/GNU/src/gcc/libjava/java/net/URLClassLoader.java

    • Property cvs2svn:cvs-rev changed from 1.1 to 1.1.1.2
    r1390 r1391  
    1 /* Copyright (C) 1999, 2000  Free Software Foundation
    2 
    3    This file is part of libgcj.
    4 
    5 This software is copyrighted work licensed under the terms of the
    6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
    7 details.  */
     1/* URLClassLoader.java --  ClassLoader that loads classes from one or more URLs
     2   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
     3
     4This file is part of GNU Classpath.
     5
     6GNU Classpath is free software; you can redistribute it and/or modify
     7it under the terms of the GNU General Public License as published by
     8the Free Software Foundation; either version 2, or (at your option)
     9any later version.
     10 
     11GNU Classpath is distributed in the hope that it will be useful, but
     12WITHOUT ANY WARRANTY; without even the implied warranty of
     13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14General Public License for more details.
     15
     16You should have received a copy of the GNU General Public License
     17along with GNU Classpath; see the file COPYING.  If not, write to the
     18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     1902111-1307 USA.
     20
     21Linking this library statically or dynamically with other modules is
     22making a combined work based on this library.  Thus, the terms and
     23conditions of the GNU General Public License cover the whole
     24combination.
     25
     26As a special exception, the copyright holders of this library give you
     27permission to link this library with independent modules to produce an
     28executable, regardless of the license terms of these independent
     29modules, and to copy and distribute the resulting executable under
     30terms of your choice, provided that you also meet, for each linked
     31independent module, the terms and conditions of the license of that
     32module.  An independent module is a module which is not derived from
     33or based on this library.  If you modify this library, you may extend
     34this exception to your version of the library, but you are not
     35obligated to do so.  If you do not wish to do so, delete this
     36exception statement from your version. */
    837
    938package java.net;
    1039
    11 import java.io.*;
    12 import java.util.jar.*;
     40import java.io.ByteArrayOutputStream;
     41import java.io.EOFException;
     42import java.io.File;
     43import java.io.FileInputStream;
     44import java.io.FileNotFoundException;
     45import java.io.FilterInputStream;
     46import java.io.FilePermission;
     47import java.io.InputStream;
     48import java.io.IOException;
     49import java.security.AccessController;
     50import java.security.AccessControlContext;
     51import java.security.CodeSource;
     52import java.security.SecureClassLoader;
     53import java.security.PrivilegedAction;
     54import java.security.PermissionCollection;
     55import java.security.cert.Certificate;
    1356import java.util.Enumeration;
    1457import java.util.Vector;
    15 
    16 public class URLClassLoader extends ClassLoader
     58import java.util.HashMap;
     59import java.util.jar.Attributes;
     60import java.util.jar.JarEntry;
     61import java.util.jar.JarFile;
     62import java.util.jar.Manifest;
     63import java.util.zip.ZipException;
     64
     65/**
     66 * A secure class loader that can load classes and resources from
     67 * multiple locations.  Given an array of <code>URL</code>s this class
     68 * loader will retrieve classes and resources by fetching them from
     69 * possible remote locations.  Each <code>URL</code> is searched in
     70 * order in which it was added.  If the file portion of the
     71 * <code>URL</code> ends with a '/' character then it is interpreted
     72 * as a base directory, otherwise it is interpreted as a jar file from
     73 * which the classes/resources are resolved.
     74 *
     75 * <p>New instances can be created by two static
     76 * <code>newInstance()</code> methods or by three public
     77 * contructors. Both ways give the option to supply an initial array
     78 * of <code>URL</code>s and (optionally) a parent classloader (that is
     79 * different from the standard system class loader).</p>
     80 *
     81 * <p>Normally creating a <code>URLClassLoader</code> throws a
     82 * <code>SecurityException</code> if a <code>SecurityManager</code> is
     83 * installed and the <code>checkCreateClassLoader()</code> method does
     84 * not return true.  But the <code>newInstance()</code> methods may be
     85 * used by any code as long as it has permission to acces the given
     86 * <code>URL</code>s.  <code>URLClassLoaders</code> created by the
     87 * <code>newInstance()</code> methods also explicitly call the
     88 * <code>checkPackageAccess()</code> method of
     89 * <code>SecurityManager</code> if one is installed before trying to
     90 * load a class.  Note that only subclasses of
     91 * <code>URLClassLoader</code> can add new URLs after the
     92 * URLClassLoader had been created. But it is always possible to get
     93 * an array of all URLs that the class loader uses to resolve classes
     94 * and resources by way of the <code>getURLs()</code> method.</p>
     95 *
     96 * <p>Open issues:
     97 * <ul>
     98 *
     99 * <li>Should the URLClassLoader actually add the locations found in
     100 * the manifest or is this the responsibility of some other
     101 * loader/(sub)class?  (see <a
     102 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
     103 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
     104 *
     105 * <li>How does <code>definePackage()</code> and sealing work
     106 * precisely?</li>
     107 *
     108 * <li>We save and use the security context (when a created by
     109 * <code>newInstance()</code> but do we have to use it in more
     110 * places?</li>
     111 *
     112 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
     113 *
     114 * </ul>
     115 * </p>
     116 *
     117 * @since 1.2
     118 *
     119 * @author Mark Wielaard ([email protected])
     120 * @author Wu Gansha ([email protected])
     121 */
     122 
     123public class URLClassLoader extends SecureClassLoader
    17124{
    18   // The URLStreamHandlerFactory
    19   URLStreamHandlerFactory factory = null;
    20 
    21   // `path' contains simply the URL's we're using for the searching.
    22   private Vector path;
    23 
    24   // If path[n] is a zip/jar, then this holds a JarURLConnection for
    25   // that thing, otherwise, path[n] is null.
    26   private Vector info;
    27 
    28   private URLStreamHandler getHandler0 (String protocol)
    29   {
    30     if (factory != null)
    31       return factory.createURLStreamHandler(protocol);
    32     else
     125  // Class Variables
     126
     127  /**
     128   * A global cache to store mappings between URLLoader and URL,
     129   * so we can avoid do all the homework each time the same URL
     130   * comes.
     131   * XXX - Keeps these loaders forever which prevents garbage collection.
     132   */
     133  private static HashMap urlloaders = new HashMap();
     134   
     135  /**
     136   * A cache to store mappings between handler factory and its
     137   * private protocol handler cache (also a HashMap), so we can avoid
     138   * create handlers each time the same protocol comes.
     139   */
     140  private static HashMap factoryCache = new HashMap(5);
     141
     142  // Instance variables
     143
     144  /** Locations to load classes from */
     145  private final Vector urls = new Vector();
     146
     147  /**
     148   * Store pre-parsed information for each url into this vector
     149   * each element is a URL loader, corresponding to the URL of
     150   * the same index in "urls"
     151   */
     152  private final Vector urlinfos = new Vector();
     153   
     154  /** Factory used to get the protocol handlers of the URLs */
     155  private final URLStreamHandlerFactory factory;
     156
     157  /**
     158   * The security context when created from <code>newInstance()</code>
     159   * or null when created through a normal constructor or when no
     160   * <code>SecurityManager</code> was installed.
     161   */
     162  private final AccessControlContext securityContext;
     163
     164  // Helper classes
     165 
     166  /**
     167   * A <code>URLLoader</code> contains all logic to load resources from a
     168   * given base <code>URL</code>.
     169   */
     170  static abstract class URLLoader
     171  {
     172    /**
     173     * Our classloader to get info from if needed.
     174     */
     175    final URLClassLoader classloader;
     176
     177    /**
     178     * The base URL from which all resources are loaded.
     179     */
     180    final URL baseURL;
     181
     182    /**
     183     * A <code>CodeSource</code> without any associated certificates.
     184     * It is common for classes to not have certificates associated
     185     * with them.  If they come from the same <code>URLLoader</code>
     186     * then it is safe to share the associated <code>CodeSource</code>
     187     * between them since <code>CodeSource</code> is immutable.
     188     */
     189    final CodeSource noCertCodeSource;
     190
     191    URLLoader(URLClassLoader classloader, URL baseURL)
     192    {
     193      this.classloader = classloader;
     194      this.baseURL = baseURL;
     195      this.noCertCodeSource = new CodeSource(baseURL, null);
     196    }
     197
     198    /**
     199     * Returns a <code>Resource</code> loaded by this
     200     * <code>URLLoader</code>, or <code>null</code> when no
     201     * <code>Resource</code> with the given name exists.
     202     */
     203    abstract Resource getResource(String s);
     204
     205    /**
     206     * Returns the <code>Manifest</code> associated with the
     207     * <code>Resource</code>s loaded by this <code>URLLoader</code> or
     208     * <code>null</code> there is no such <code>Manifest</code>.
     209     */
     210    Manifest getManifest()
     211    {
    33212      return null;
    34   }
    35 
    36   public URLClassLoader (URL[] urls)
    37   {
    38     this (urls, null, null);
    39   }
    40  
    41   public URLClassLoader (URL[] urls, ClassLoader parent)
    42   {
    43     this (urls, parent, null);
    44   }
    45 
    46   // A File URL may actually be a Jar URL.  Convert if possible.
    47   private URL jarFileize (URL url)
    48   {
    49     if (! url.getProtocol ().equals ("jar"))
     213    }
     214  }
     215
     216  /**
     217   * A <code>Resource</code> represents a resource in some
     218   * <code>URLLoader</code>. It also contains all information (e.g.,
     219   * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
     220   * <code>InputStream</code>) that is necessary for loading resources
     221   * and creating classes from a <code>URL</code>.
     222   */
     223  static abstract class Resource
     224  {
     225    final URLLoader loader;
     226    final String name;
     227
     228    Resource(URLLoader loader, String name)
     229    {
     230      this.loader = loader;
     231      this.name = name;
     232    }
     233
     234    /**
     235     * Returns the non-null <code>CodeSource</code> associated with
     236     * this resource.
     237     */
     238    CodeSource getCodeSource()
     239    {
     240      Certificate[] certs = getCertificates();
     241      if (certs == null)
     242        return loader.noCertCodeSource;
     243      else
     244        return new CodeSource(loader.baseURL, certs);
     245    }
     246
     247    /**
     248     * Returns <code>Certificates</code> associated with this
     249     * resource, or null when there are none.
     250     */
     251    Certificate[] getCertificates()
     252    {
     253      return null;
     254    }
     255
     256    /**
     257     * Return a <code>URL</code> that can be used to access this resource.
     258     */
     259    abstract URL getURL();
     260
     261    /**
     262     * Returns the size of this <code>Resource</code> in bytes or
     263     * <code>-1</code> when unknown.
     264     */
     265    abstract int getLength();
     266
     267    /**
     268     * Returns the non-null <code>InputStream</code> through which
     269     * this resource can be loaded.
     270     */
     271    abstract InputStream getInputStream() throws IOException;
     272  }
     273
     274  /**
     275   * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
     276   * only loading from jar url.
     277   */
     278  final static class JarURLLoader extends URLLoader
     279  {
     280    final JarFile jarfile; // The jar file for this url
     281    final URL baseJarURL;  // Base jar: url for all resources loaded from jar
     282
     283    public JarURLLoader(URLClassLoader classloader, URL baseURL)
     284    {
     285      super(classloader, baseURL);
     286
     287      // cache url prefix for all resources in this jar url
     288      String external = baseURL.toExternalForm();
     289      StringBuffer sb = new StringBuffer(external.length() + 6);
     290      sb.append("jar:");
     291      sb.append(external);
     292      sb.append("!/");
     293      String jarURL = sb.toString();
     294
     295      URL baseJarURL = null;
     296      JarFile jarfile = null;
     297      try
     298        {
     299          baseJarURL
     300            = new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
     301          jarfile
     302            = ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
     303        }
     304      catch (IOException ioe) { /* ignored */ }
     305
     306      this.baseJarURL = baseJarURL;
     307      this.jarfile = jarfile;
     308    }
     309
     310    /** get resource with the name "name" in the jar url */
     311    Resource getResource(String name)
     312    {
     313      if (jarfile == null)
     314        return null;
     315
     316      JarEntry je = jarfile.getJarEntry(name);
     317      if(je != null)
     318        return new JarURLResource(this, name, je);
     319      else
     320        return null;
     321    }
     322
     323    Manifest getManifest()
     324    {
     325      try
     326        {
     327          return (jarfile == null) ? null : jarfile.getManifest();
     328        }
     329      catch (IOException ioe)
     330        {
     331          return null;
     332        }
     333    }
     334  }
     335
     336  final static class JarURLResource extends Resource
     337  {
     338    private final JarEntry entry;
     339
     340    JarURLResource(JarURLLoader loader, String name, JarEntry entry)
     341    {
     342      super(loader, name);
     343      this.entry = entry;
     344    }
     345
     346    InputStream getInputStream() throws IOException
     347    {
     348      return ((JarURLLoader)loader).jarfile.getInputStream(entry);
     349    }
     350
     351    int getLength()
     352    {
     353      return (int)entry.getSize();
     354    }
     355
     356    Certificate[] getCertificates()
     357    {
     358      return entry.getCertificates();
     359    }
     360
     361    URL getURL()
     362    {
     363      try
     364        {
     365          return new URL(((JarURLLoader)loader).baseJarURL, name,
     366                         loader.classloader.getURLStreamHandler("jar"));
     367        }
     368      catch(MalformedURLException e)
     369        {
     370          InternalError ie = new InternalError();
     371          ie.initCause(e);
     372          throw ie;
     373        }
     374    }
     375  }
     376
     377  /**
     378   * Loader for remote directories.
     379   */
     380  final static class RemoteURLLoader extends URLLoader
     381  {
     382    final private String protocol;
     383
     384    RemoteURLLoader(URLClassLoader classloader, URL url)
     385    {
     386      super(classloader, url);
     387      protocol = url.getProtocol();
     388    }
     389
     390    /**
     391     * Get a remote resource.
     392     * Returns null if no such resource exists.
     393     */
     394    Resource getResource(String name)
     395    {
     396      try
     397        {
     398          URL url = new URL(baseURL, name,
     399                            classloader.getURLStreamHandler(protocol));
     400          URLConnection connection = url.openConnection();
     401
     402          // Open the connection and check the stream
     403          // just to be sure it exists.
     404          int length = connection.getContentLength();
     405          InputStream stream = connection.getInputStream();
     406
     407          // We can do some extra checking if it is a http request
     408          if (connection instanceof HttpURLConnection)
     409            {
     410              int response
     411                = ((HttpURLConnection)connection).getResponseCode();
     412              if (response/100 != 2)
     413                return null;
     414            }
     415
     416          if (stream != null)
     417            return new RemoteResource(this, name, url, stream, length);
     418          else
     419            return null;
     420        }
     421      catch (IOException ioe)
     422        {
     423          return null;
     424        }
     425    }
     426  }
     427
     428  /**
     429   * A resource from some remote location.
     430   */
     431  final static class RemoteResource extends Resource
     432  {
     433    final private URL url;
     434    final private InputStream stream;
     435    final private int length;
     436
     437    RemoteResource(RemoteURLLoader loader, String name, URL url,
     438                   InputStream stream, int length)
     439    {
     440      super(loader, name);
     441      this.url = url;
     442      this.stream = stream;
     443      this.length = length;
     444    }
     445
     446    InputStream getInputStream() throws IOException
     447    {
     448      return stream;
     449    }
     450                       
     451    public int getLength()
     452    {
     453      return length;
     454    }
     455               
     456    public URL getURL()
     457    {
     458      return url;
     459    }
     460  }
     461
     462  /**
     463   * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
     464   * only loading from file url.
     465   */
     466  final static class FileURLLoader extends URLLoader
     467  {
     468    File dir;   //the file for this file url
     469
     470    FileURLLoader(URLClassLoader classloader, URL url)
     471    {
     472      super(classloader, url);
     473      dir = new File(baseURL.getFile());
     474    }
     475
     476    /** get resource with the name "name" in the file url */
     477    Resource getResource(String name)
     478    {
     479      File file = new File(dir, name);
     480      if (file.exists() && !file.isDirectory())
     481        return new FileResource(this, name, file);
     482      return null;
     483    }
     484  }
     485
     486  final static class FileResource extends Resource
     487  {
     488    final File file;
     489
     490    FileResource(FileURLLoader loader, String name, File file)
     491    {
     492      super(loader, name);
     493      this.file = file;
     494    }
     495
     496    InputStream getInputStream() throws IOException
     497    {
     498      return new FileInputStream(file);
     499    }
     500                       
     501    public int getLength()
     502    {
     503      return (int)file.length();
     504    }
     505
     506    public URL getURL()
     507    {
     508      try
     509        {
     510          return new URL(loader.baseURL, name,
     511                         loader.classloader.getURLStreamHandler("file"));
     512        }
     513      catch(MalformedURLException e)
     514        {
     515          InternalError ie = new InternalError();
     516          ie.initCause(e);
     517          throw ie;
     518        }
     519    }
     520  }
     521   
     522  // Constructors
     523
     524  /**
     525   * Creates a URLClassLoader that gets classes from the supplied URLs.
     526   * To determine if this classloader may be created the constructor of
     527   * the super class (<code>SecureClassLoader</code>) is called first, which
     528   * can throw a SecurityException. Then the supplied URLs are added
     529   * in the order given to the URLClassLoader which uses these URLs to
     530   * load classes and resources (after using the default parent ClassLoader).
     531   *
     532   * @exception SecurityException if the SecurityManager disallows the
     533   * creation of a ClassLoader.
     534   * @param urls Locations that should be searched by this ClassLoader when
     535   * resolving Classes or Resources.
     536   * @see SecureClassLoader
     537   */
     538  public URLClassLoader(URL[] urls) throws SecurityException
     539  {
     540    super();
     541    this.factory = null;
     542    this.securityContext = null;
     543    addURLs(urls);
     544  }
     545
     546  /**
     547   * Private constructor used by the static
     548   * <code>newInstance(URL[])</code> method.  Creates an
     549   * <code>URLClassLoader</code> without any <code>URL</code>s
     550   * yet. This is used to bypass the normal security check for
     551   * creating classloaders, but remembers the security context which
     552   * will be used when defining classes.  The <code>URL</code>s to
     553   * load from must be added by the <code>newInstance()</code> method
     554   * in the security context of the caller.
     555   *
     556   * @param securityContext the security context of the unprivileged code.
     557   */
     558  private URLClassLoader(AccessControlContext securityContext)
     559  {
     560    super();
     561    this.factory = null;
     562    this.securityContext = securityContext;
     563  }
     564
     565  /**
     566   * Creates a <code>URLClassLoader</code> that gets classes from the supplied
     567   * <code>URL</code>s.
     568   * To determine if this classloader may be created the constructor of
     569   * the super class (<code>SecureClassLoader</code>) is called first, which
     570   * can throw a SecurityException. Then the supplied URLs are added
     571   * in the order given to the URLClassLoader which uses these URLs to
     572   * load classes and resources (after using the supplied parent ClassLoader).
     573   * @exception SecurityException if the SecurityManager disallows the
     574   * creation of a ClassLoader.
     575   * @exception SecurityException
     576   * @param urls Locations that should be searched by this ClassLoader when
     577   * resolving Classes or Resources.
     578   * @param parent The parent class loader used before trying this class
     579   * loader.
     580   * @see SecureClassLoader
     581   */
     582  public URLClassLoader(URL[] urls, ClassLoader parent)
     583    throws SecurityException
     584  {
     585    super(parent);
     586    this.factory = null;
     587    this.securityContext = null;
     588    addURLs(urls);
     589  }
     590
     591  /**
     592   * Private constructor used by the static
     593   * <code>newInstance(URL[])</code> method.  Creates an
     594   * <code>URLClassLoader</code> with the given parent but without any
     595   * <code>URL</code>s yet. This is used to bypass the normal security
     596   * check for creating classloaders, but remembers the security
     597   * context which will be used when defining classes.  The
     598   * <code>URL</code>s to load from must be added by the
     599   * <code>newInstance()</code> method in the security context of the
     600   * caller.
     601   *
     602   * @param securityContext the security context of the unprivileged code.
     603   */
     604  private URLClassLoader(ClassLoader parent,
     605                         AccessControlContext securityContext)
     606  {
     607    super(parent);
     608    this.factory = null;
     609    this.securityContext = securityContext;
     610  }
     611
     612  /**
     613   * Creates a URLClassLoader that gets classes from the supplied URLs.
     614   * To determine if this classloader may be created the constructor of
     615   * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
     616   * can throw a SecurityException. Then the supplied URLs are added
     617   * in the order given to the URLClassLoader which uses these URLs to
     618   * load classes and resources (after using the supplied parent ClassLoader).
     619   * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
     620   * protocol handlers of the supplied URLs.
     621   * @exception SecurityException if the SecurityManager disallows the
     622   * creation of a ClassLoader.
     623   * @exception SecurityException
     624   * @param urls Locations that should be searched by this ClassLoader when
     625   * resolving Classes or Resources.
     626   * @param parent The parent class loader used before trying this class
     627   * loader.
     628   * @param factory Used to get the protocol handler for the URLs.
     629   * @see SecureClassLoader
     630   */
     631  public URLClassLoader(URL[] urls,
     632                        ClassLoader parent,
     633                        URLStreamHandlerFactory factory)
     634    throws SecurityException
     635  {
     636    super(parent);
     637    this.securityContext = null;
     638    this.factory = factory;
     639    addURLs(urls);
     640
     641    // If this factory is still not in factoryCache, add it,
     642    //   since we only support three protocols so far, 5 is enough
     643    //   for cache initial size
     644    synchronized(factoryCache)
    50645      {
    51         String f = url.getFile ();
    52 
    53         // If it ends with '/' we'll take it for a directory,
    54         // otherwise it's a jar file.  This is how JDK 1.2 defines
    55         // it, so we will not try to be smart here.
    56         if (f.charAt (f.length ()-1) != '/')
     646        if(factory != null && factoryCache.get(factory) == null)
     647          factoryCache.put(factory, new HashMap(5));
     648      }
     649  }
     650
     651  // Methods
     652
     653  /**
     654   * Adds a new location to the end of the internal URL store.
     655   * @param newUrl the location to add
     656   */
     657  protected void addURL(URL newUrl)
     658  {
     659    synchronized(urlloaders)
     660      {
     661        if (newUrl == null)
     662          return; // Silently ignore...
     663       
     664        // check global cache to see if there're already url loader
     665        // for this url
     666        URLLoader loader = (URLLoader)urlloaders.get(newUrl);
     667        if (loader == null)
    57668          {
    58             try
     669            String file = newUrl.getFile();
     670            // Check that it is not a directory
     671            if (! (file.endsWith("/") || file.endsWith(File.separator)))
     672              loader = new JarURLLoader(this, newUrl);
     673            else if ("file".equals(newUrl.getProtocol()))
     674              loader = new FileURLLoader(this, newUrl);
     675            else
     676              loader = new RemoteURLLoader(this, newUrl);
     677
     678            // cache it
     679            urlloaders.put(newUrl, loader);
     680          }
     681
     682        urls.add(newUrl);
     683        urlinfos.add(loader);
     684      }
     685  }
     686
     687  /**
     688   * Adds an array of new locations to the end of the internal URL store.
     689   * @param newUrls the locations to add
     690   */
     691  private void addURLs(URL[] newUrls)
     692  {
     693    for (int i = 0; i < newUrls.length; i++)
     694    {
     695      addURL(newUrls[i]);
     696    }
     697  }
     698
     699  /**
     700   * Defines a Package based on the given name and the supplied manifest
     701   * information. The manifest indicates the tile, version and
     702   * vendor information of the specification and implementation and wheter the
     703   * package is sealed. If the Manifest indicates that the package is sealed
     704   * then the Package will be sealed with respect to the supplied URL.
     705   *
     706   * @exception IllegalArgumentException If this package name already exists
     707   * in this class loader
     708   * @param name The name of the package
     709   * @param manifest The manifest describing the specification,
     710   * implementation and sealing details of the package
     711   * @param url the code source url to seal the package
     712   * @return the defined Package
     713   */
     714  protected Package definePackage(String name, Manifest manifest, URL url)
     715    throws IllegalArgumentException
     716  {
     717    Attributes attr = manifest.getMainAttributes();
     718    String specTitle =
     719      attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
     720    String specVersion =
     721      attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
     722    String specVendor =
     723      attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
     724    String implTitle =
     725      attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
     726    String implVersion =
     727      attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
     728    String implVendor =
     729      attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
     730
     731    // Look if the Manifest indicates that this package is sealed
     732    // XXX - most likely not completely correct!
     733    // Shouldn't we also check the sealed attribute of the complete jar?
     734    // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
     735    // But how do we get that jar manifest here?
     736    String sealed = attr.getValue(Attributes.Name.SEALED);
     737    if ("false".equals(sealed))
     738    {
     739      // make sure that the URL is null so the package is not sealed
     740      url = null;
     741    }
     742
     743    return definePackage(name, specTitle, specVersion, specVendor,
     744                         implTitle, implVersion, implVendor, url);
     745  }
     746
     747  /**
     748   * Finds (the first) class by name from one of the locations. The locations
     749   * are searched in the order they were added to the URLClassLoader.
     750   *
     751   * @param className the classname to find
     752   * @exception ClassNotFoundException when the class could not be found or
     753   * loaded
     754   * @return a Class object representing the found class
     755   */
     756  protected Class findClass(final String className)
     757    throws ClassNotFoundException
     758  {
     759    // Just try to find the resource by the (almost) same name
     760    String resourceName = className.replace('.', '/') + ".class";
     761    Resource resource = findURLResource(resourceName);
     762    if (resource == null)
     763      throw new ClassNotFoundException(className + " not found in " + urls);
     764
     765    // Try to read the class data, create the CodeSource, Package and
     766    // construct the class (and watch out for those nasty IOExceptions)
     767    try
     768      {
     769        byte [] data;
     770        InputStream in = resource.getInputStream();
     771        int length = resource.getLength();
     772        if (length != -1)
     773          {
     774            // We know the length of the data.
     775            // Just try to read it in all at once
     776            data = new byte[length];
     777            int pos = 0;
     778            while(length - pos > 0)
    59779              {
    60                 url = new URL ("jar", "", -1, (url.toExternalForm ())+"!/",
    61                                getHandler0 ("jar"));
    62               }
    63             catch (MalformedURLException x)
    64               {
    65                 /* ignore */
     780                int len = in.read(data, pos, length - pos);
     781                if (len == -1)
     782                  throw new EOFException("Not enough data reading from: "
     783                                         + in);
     784                pos += len;
    66785              }
    67           }
    68       }
    69     return url;
    70   }
    71 
    72   protected void addURL (URL url)
    73   {
    74     JarURLConnection conn = null;
    75    
    76     // Convert a Jar File URL into Jar URL if possible.
    77     url = jarFileize (url);
    78 
    79     path.addElement (url);
    80 
    81     if (url.getProtocol ().equals ("jar"))
    82       {
    83         try
    84           {
    85             conn = (JarURLConnection) url.openConnection ();
    86           }
    87         catch (java.io.IOException x)
    88           {
    89             /* ignore */
    90           }
    91       }
    92 
    93     info.addElement (conn);
    94   }
    95 
    96   public URLClassLoader (URL[] urls, ClassLoader parent,
    97                          URLStreamHandlerFactory fac)
    98   {
    99     super (parent);
    100 
    101     factory = fac;
    102 
    103     if (urls == null || urls.length == 0)
    104       {
    105         path = new Vector (1);
    106         info = new Vector (1);
    107         return;
    108       }
    109 
    110     path = new Vector (urls.length);
    111     info = new Vector (urls.length);
    112 
    113     for (int i = 0; i < urls.length; i++)
    114       {
    115         // Convert a Jar File URL into a Jar URL is possible.
    116         URL u = jarFileize(urls[i]);
    117 
    118         path.addElement (u);
    119 
    120         if (u.getProtocol ().equals ("jar"))
    121           {
    122             JarURLConnection conn = null;
    123             try
    124               {
    125                 conn = (JarURLConnection) u.openConnection ();
    126               }
    127             catch (java.io.IOException x)
    128               {
    129                 /* ignore */
    130               }
    131             info.addElement (conn);
    132786          }
    133787        else
    134788          {
    135             info.addElement (null);
     789            // We don't know the data length.
     790            // Have to read it in chunks.
     791            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
     792            byte b[] = new byte[4096];
     793            int l = 0;
     794            while (l != -1)
     795              {
     796                l = in.read(b);
     797                if (l != -1)
     798                  out.write(b, 0, l);
     799              }
     800            data = out.toByteArray();
     801          }
     802        final byte[] classData = data;
     803
     804        // Now get the CodeSource
     805        final CodeSource source = resource.getCodeSource();
     806       
     807        // Find out package name
     808        String packageName = null;
     809        int lastDot = className.lastIndexOf('.');
     810        if (lastDot != -1)
     811          packageName = className.substring(0, lastDot);
     812       
     813        if (packageName != null && getPackage(packageName) == null)
     814          {
     815            // define the package
     816            Manifest manifest = resource.loader.getManifest();
     817            if (manifest == null)
     818              definePackage(packageName,
     819                            null, null, null, null, null, null, null);
     820            else
     821              definePackage(packageName, manifest, resource.loader.baseURL);
     822          }
     823       
     824        // And finally construct the class!
     825        SecurityManager sm = System.getSecurityManager();
     826        if (sm != null && securityContext != null)
     827          {
     828            return (Class)AccessController.doPrivileged
     829              (new PrivilegedAction()
     830                {
     831                  public Object run()
     832                  {
     833                    return defineClass(className, classData,
     834                                       0, classData.length,
     835                                       source);
     836                  }
     837                }, securityContext);
     838          }
     839        else
     840          return defineClass(className, classData,
     841                             0, classData.length,
     842                             source);
     843      }
     844    catch (IOException ioe)
     845      {
     846        throw new ClassNotFoundException(className, ioe);
     847      }
     848  }
     849
     850  /**
     851   * Finds the first occurrence of a resource that can be found. The locations
     852   * are searched in the order they were added to the URLClassLoader.
     853   *
     854   * @param resourceName the resource name to look for
     855   * @return the URLResource for the resource if found, null otherwise
     856   */
     857  private Resource findURLResource(String resourceName)
     858  {
     859    int max = urls.size();
     860    for (int i = 0; i < max; i++)
     861      {
     862        URLLoader loader = (URLLoader)urlinfos.elementAt(i);
     863        if (loader == null)
     864          continue;
     865       
     866        Resource resource = loader.getResource(resourceName);
     867        if (resource != null)
     868          return resource;
     869      }
     870    return null;
     871  }
     872
     873  /**
     874   * Finds the first occurrence of a resource that can be found.
     875   *
     876   * @param resourceName the resource name to look for
     877   * @return the URL if found, null otherwise
     878   */
     879  public URL findResource(String resourceName)
     880  {
     881    Resource resource = findURLResource(resourceName);
     882    if (resource != null)
     883      return resource.getURL();
     884   
     885    // Resource not found
     886    return null;
     887  }
     888
     889  /**
     890   * If the URLStreamHandlerFactory has been set this return the appropriate
     891   * URLStreamHandler for the given protocol, if not set returns null.
     892   *
     893   * @param protocol the protocol for which we need a URLStreamHandler
     894   * @return the appropriate URLStreamHandler or null
     895   */
     896  URLStreamHandler getURLStreamHandler(String protocol)
     897  {
     898    if (factory == null)
     899      return null;
     900
     901    URLStreamHandler handler;
     902    synchronized (factoryCache)
     903      {
     904        // check if there're handler for the same protocol in cache
     905        HashMap cache = (HashMap)factoryCache.get(factory);
     906        handler = (URLStreamHandler)cache.get(protocol);
     907        if(handler == null)
     908          {
     909            // add it to cache
     910            handler = factory.createURLStreamHandler(protocol);
     911            cache.put(protocol, handler);
    136912          }
    137913      }
    138   }
    139 
    140   public URL[] getURLs ()
    141   {
    142     URL[] urls = new URL[path.size()];
    143     path.copyInto (urls);
    144     return urls;
    145   }
    146  
    147   public Enumeration findResources (String name)
    148   {
    149     Vector results = new Vector ();
    150 
    151     for (int i = 0; i < path.size(); i++)
     914    return handler;
     915  }
     916
     917  /**
     918   * Finds all the resources with a particular name from all the locations.
     919   *
     920   * @exception IOException when an error occurs accessing one of the
     921   * locations
     922   * @param resourceName the name of the resource to lookup
     923   * @return a (possible empty) enumeration of URLs where the resource can be
     924   * found
     925   */
     926  public Enumeration findResources(String resourceName) throws IOException
     927  {
     928    Vector resources = new Vector();
     929    int max = urls.size();
     930    for (int i = 0; i < max; i++)
    152931      {
    153         URL u = (URL)path.elementAt (i);
    154                
    155         try {
    156           JarURLConnection conn = (JarURLConnection) info.elementAt (i);
    157          
    158           if (conn != null)
     932        URLLoader loader = (URLLoader)urlinfos.elementAt(i);
     933        Resource resource = loader.getResource(resourceName);
     934        if (resource != null)
     935          resources.add(resource.getURL());
     936      }
     937    return resources.elements();
     938  }
     939
     940  /**
     941   * Returns the permissions needed to access a particular code
     942   * source.  These permissions includes those returned by
     943   * <code>SecureClassLoader.getPermissions()</code> and the actual
     944   * permissions to access the objects referenced by the URL of the
     945   * code source.  The extra permissions added depend on the protocol
     946   * and file portion of the URL in the code source. If the URL has
     947   * the "file" protocol ends with a '/' character then it must be a
     948   * directory and a file Permission to read everything in that
     949   * directory and all subdirectories is added. If the URL had the
     950   * "file" protocol and doesn't end with a '/' character then it must
     951   * be a normal file and a file permission to read that file is
     952   * added. If the <code>URL</code> has any other protocol then a
     953   * socket permission to connect and accept connections from the host
     954   * portion of the URL is added.
     955   *
     956   * @param source The codesource that needs the permissions to be accessed
     957   * @return the collection of permissions needed to access the code resource
     958   * @see java.security.SecureClassLoader#getPermissions()
     959   */
     960  protected PermissionCollection getPermissions(CodeSource source)
     961  {
     962    // XXX - This implementation does exactly as the Javadoc describes.
     963    // But maybe we should/could use URLConnection.getPermissions()?
     964
     965    // First get the permissions that would normally be granted
     966    PermissionCollection permissions = super.getPermissions(source);
     967       
     968    // Now add the any extra permissions depending on the URL location
     969    URL url = source.getLocation();
     970    String protocol = url.getProtocol();
     971    if (protocol.equals("file"))
     972      {
     973        String file = url.getFile();
     974        // If the file end in / it must be an directory
     975        if (file.endsWith("/") || file.endsWith(File.separator))
     976          {
     977            // Grant permission to read everything in that directory and
     978            // all subdirectories
     979            permissions.add(new FilePermission(file + "-", "read"));
     980          }
     981        else
     982          {
     983            // It is a 'normal' file
     984            // Grant permission to access that file
     985            permissions.add(new FilePermission(file, "read"));
     986          }
     987      }
     988    else
     989      {
     990        // Grant permission to connect to and accept connections from host
     991        String host = url.getHost();
     992        if (host != null)
     993          permissions.add(new SocketPermission(host, "connect,accept"));
     994      }
     995
     996    return permissions;
     997  }
     998   
     999  /**
     1000   * Returns all the locations that this class loader currently uses the
     1001   * resolve classes and resource. This includes both the initially supplied
     1002   * URLs as any URLs added later by the loader.
     1003   * @return All the currently used URLs
     1004   */
     1005  public URL[] getURLs()
     1006  {
     1007    return (URL[]) urls.toArray(new URL[urls.size()]);
     1008  }
     1009
     1010  /**
     1011   * Creates a new instance of a <code>URLClassLoader</code> that gets
     1012   * classes from the supplied <code>URL</code>s. This class loader
     1013   * will have as parent the standard system class loader.
     1014   *
     1015   * @param urls the initial URLs used to resolve classes and
     1016   * resources
     1017   *
     1018   * @exception SecurityException when the calling code does not have
     1019   * permission to access the given <code>URL</code>s
     1020   */
     1021  public static URLClassLoader newInstance(URL urls[])
     1022    throws SecurityException
     1023  {
     1024    return newInstance(urls, null);
     1025  }
     1026
     1027  /**
     1028   * Creates a new instance of a <code>URLClassLoader</code> that gets
     1029   * classes from the supplied <code>URL</code>s and with the supplied
     1030   * loader as parent class loader.
     1031   *
     1032   * @param urls the initial URLs used to resolve classes and
     1033   * resources
     1034   * @param parent the parent class loader
     1035   *
     1036   * @exception SecurityException when the calling code does not have
     1037   * permission to access the given <code>URL</code>s
     1038   */
     1039  public static URLClassLoader newInstance(URL urls[],
     1040                                           final ClassLoader parent)
     1041    throws SecurityException
     1042  {
     1043    SecurityManager sm = System.getSecurityManager();
     1044    if (sm == null)
     1045      return new URLClassLoader(urls, parent);
     1046    else
     1047      {
     1048        final Object securityContext = sm.getSecurityContext();
     1049        // XXX - What to do with anything else then an AccessControlContext?
     1050        if (!(securityContext instanceof AccessControlContext))
     1051          throw new SecurityException
     1052            ("securityContext must be AccessControlContext: "
     1053             + securityContext);
     1054       
     1055        URLClassLoader loader =
     1056          (URLClassLoader)AccessController.doPrivileged(new PrivilegedAction()
    1591057            {
    160               if (conn.getJarFile().getJarEntry (name) != null)
    161                 results.addElement (new URL(u, name, getHandler0 (u.getProtocol())));
    162             }
    163           else
    164             {
    165               URL p = new URL (u, name, getHandler0 (u.getProtocol()));
    166                            
    167               InputStream is = p.openStream();
    168               if (is != null)
    169                 {
    170                   is.close();
    171                   results.addElement (p);
    172                 }
    173             }
    174                    
    175           // if we get an exception ... try the next path element
    176         } catch (IOException x) {
    177           continue;
    178         }
     1058              public Object run()
     1059              {
     1060                return new URLClassLoader
     1061                  (parent, (AccessControlContext)securityContext);
     1062              }
     1063            });
     1064        loader.addURLs(urls);
     1065        return loader;
    1791066      }
    180        
    181     return results.elements ();
    182   }
    183 
    184   public URL findResource (String name)
    185   {
    186     for (int i = 0; i < path.size(); i++)
    187       {
    188         URL u = (URL)path.elementAt (i);
    189        
    190         try {
    191           JarURLConnection conn = (JarURLConnection) info.elementAt (i);
    192          
    193           if (conn != null)
    194             {
    195               if (conn.getJarFile().getJarEntry (name) != null)
    196                 return new URL(u, name, getHandler0 (u.getProtocol()));
    197             }
    198           else
    199             {
    200               URL p = new URL (u, name, getHandler0 (u.getProtocol()));
    201 
    202               InputStream is = p.openStream();
    203               if (is != null)
    204                 {
    205                   is.close();
    206                   return p;
    207                 }
    208             }
    209        
    210           // if we get an exception ... try the next path element
    211         } catch (IOException x) {
    212           continue;
    213         }
    214       }
    215 
    216     return null;
    217   }
    218 
    219   // and finally, we can implement our class loader functionality.
    220   protected Class findClass (String name)
    221     throws ClassNotFoundException
    222   {
    223     if (name == null)
    224       throw new ClassNotFoundException ("null");
    225 
    226     try
    227       {
    228         URL u = getResource (name.replace ('.', '/') + ".class");
    229 
    230         if (u == null)
    231           throw new ClassNotFoundException (name);
    232 
    233         URLConnection connection = u.openConnection ();
    234         InputStream is = connection.getInputStream ();
    235 
    236         int len = connection.getContentLength ();
    237         byte[] data = new byte[len];
    238 
    239         int left = len;
    240         int off  = 0;
    241         while (left > 0)
    242           {
    243             int c = is.read (data, off, len-off);
    244             if (c == -1 || c == 0)
    245               throw new InternalError ("premature end of file");
    246             left -= c;
    247             off += c;
    248           }
    249 
    250         return defineClass (name, data, 0, len);
    251       }
    252     catch (java.io.IOException x)
    253       {
    254         throw new ClassNotFoundException(name);
    255       }
    2561067  }
    2571068}
    258 
Note: See TracChangeset for help on using the changeset viewer.