1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs
- Copyright (C) 1999, 2000, 2001, 2002 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., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 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.FileNotFoundException;
- import java.io.FilterInputStream;
- import java.io.FilePermission;
- import java.io.InputStream;
- import java.io.IOException;
- import java.security.AccessController;
- import java.security.AccessControlContext;
- import java.security.CodeSource;
- import java.security.SecureClassLoader;
- import java.security.PrivilegedAction;
- import java.security.PermissionCollection;
- import java.security.cert.Certificate;
- import java.util.Enumeration;
- import java.util.Vector;
- import java.util.HashMap;
- import java.util.jar.Attributes;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
- import java.util.jar.Manifest;
- import java.util.zip.ZipException;
- /**
- * 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, corresponding to the URL of
- * the same index in "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>.
- */
- static abstract class URLLoader
- {
- /**
- * Our classloader to get info from if needed.
- */
- final URLClassLoader classloader;
- /**
- * The base URL from which all resources are loaded.
- */
- final URL baseURL;
- /**
- * 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 = classloader;
- this.baseURL = baseURL;
- this.noCertCodeSource = new CodeSource(baseURL, 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;
- }
- }
- /**
- * 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>.
- */
- static abstract 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.
- */
- final static 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
- 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();
- URL baseJarURL = null;
- JarFile jarfile = null;
- try
- {
- baseJarURL
- = new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
- jarfile
- = ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
- }
- 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;
- 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;
- }
- }
- }
- final static 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()
- {
- return entry.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.
- */
- final static class RemoteURLLoader extends URLLoader
- {
- final private 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.
- */
- final static class RemoteResource extends Resource
- {
- final private URL url;
- final private InputStream stream;
- final private 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>FileURLLoader</code> is a type of <code>URLLoader</code>
- * only loading from file url.
- */
- final static 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)
- {
- File file = new File(dir, name);
- if (file.exists() && !file.isDirectory())
- return new FileResource(this, name, file);
- return null;
- }
- }
- final static class FileResource extends Resource
- {
- final File file;
- FileResource(FileURLLoader loader, String name, File file)
- {
- super(loader, name);
- this.file = file;
- }
- InputStream getInputStream() throws IOException
- {
- return new FileInputStream(file);
- }
-
- public int getLength()
- {
- 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;
- }
- }
- }
-
- // 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);
- }
- /**
- * 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.
- */
- private 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)
- {
- synchronized(urlloaders)
- {
- if (newUrl == null)
- return; // Silently ignore...
-
- // 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();
- // Check that it is not a directory
- if (! (file.endsWith("/") || file.endsWith(File.separator)))
- loader = new JarURLLoader(this, newUrl);
- else if ("file".equals(newUrl.getProtocol()))
- loader = new FileURLLoader(this, newUrl);
- else
- loader = new RemoteURLLoader(this, newUrl);
- // cache it
- urlloaders.put(newUrl, loader);
- }
- urls.add(newUrl);
- urlinfos.add(loader);
- }
- }
- /**
- * 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]);
- }
- }
- /**
- * Defines a Package based on the given name and the supplied manifest
- * information. The manifest indicates the tile, version and
- * vendor information of the specification and implementation and wheter 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
- {
- Attributes attr = manifest.getMainAttributes();
- String specTitle =
- attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
- String specVersion =
- attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
- String specVendor =
- attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
- String implTitle =
- attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
- String implVersion =
- attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
- String implVendor =
- attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
- // 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, specVersion, specVendor,
- implTitle, implVersion, implVendor, 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";
- Resource resource = findURLResource(resourceName);
- if (resource == null)
- throw new ClassNotFoundException(className + " not found in " + urls);
- // 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();
- if (sm != null && securityContext != null)
- {
- return (Class)AccessController.doPrivileged
- (new PrivilegedAction()
- {
- public Object run()
- {
- return defineClass(className, classData,
- 0, classData.length,
- source);
- }
- }, securityContext);
- }
- else
- return defineClass(className, classData,
- 0, classData.length,
- source);
- }
- catch (IOException ioe)
- {
- throw new ClassNotFoundException(className, ioe);
- }
- }
- /**
- * 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 = urls.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 = urls.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 the 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
- *
- * @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
- *
- * @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;
- }
- }
- }
|