From 07b78716af6a9d7c9fd1e94d9baf94a52c873947 Mon Sep 17 00:00:00 2001
From: Andrew Haley New instances can be created by two static
- * Normally creating a Open issues:
- * URLs this class
- * loader will retrieve classes and resources by fetching them from
- * possible remote locations. Each URL is searched in
- * order in which it was added. If the file portion of the
- * URL 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.
- *
- * newInstance() methods or by three public
- * contructors. Both ways give the option to supply an initial array
- * of URLs and (optionally) a parent classloader (that is
- * different from the standard system class loader).URLClassLoader throws a
- * SecurityException if a SecurityManager is
- * installed and the checkCreateClassLoader() method does
- * not return true. But the newInstance() methods may be
- * used by any code as long as it has permission to acces the given
- * URLs. URLClassLoaders created by the
- * newInstance() methods also explicitly call the
- * checkPackageAccess() method of
- * SecurityManager if one is installed before trying to
- * load a class. Note that only subclasses of
- * URLClassLoader 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 getURLs() method.
- *
- *
- * definePackage() and sealing work
- * precisely?newInstance() but do we have to use it in more
- * places?URLStreamHandlers has not been tested.
newInstance()
- * or null when created through a normal constructor or when no
- * SecurityManager was installed.
- */
- private final AccessControlContext securityContext;
-
- // Helper classes
-
- /**
- * Creates a URLClassLoader that gets classes from the supplied URLs.
- * To determine if this classloader may be created the constructor of
- * the super class (SecureClassLoader) 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).
- *
- * @param urls Locations that should be searched by this ClassLoader when
- * resolving Classes or Resources.
- * @exception SecurityException if the SecurityManager disallows the
- * creation of a ClassLoader.
- * @see SecureClassLoader
- */
- public URLClassLoader(URL[] urls) throws SecurityException
- {
- super();
- this.factory = null;
- this.securityContext = null;
- addURLs(urls);
- }
-
- /**
- * Creates a URLClassLoader that gets classes from the supplied
- * URLs.
- * To determine if this classloader may be created the constructor of
- * the super class (SecureClassLoader) 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).
- * @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.
- * @exception SecurityException if the SecurityManager disallows the
- * creation of a ClassLoader.
- * @exception SecurityException
- * @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
- * newInstance(URL[]) method. Creates an
- * URLClassLoader with the given parent but without any
- * URLs 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
- * URLs to load from must be added by the
- * newInstance() 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 (SecureClassLoader) 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 URLStreamHandlerFactory to get the
- * protocol handlers of the supplied URLs.
- * @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.
- * @exception SecurityException if the SecurityManager disallows the
- * creation of a ClassLoader.
- * @exception SecurityException
- * @see SecureClassLoader
- */
- public URLClassLoader(URL[] urls, ClassLoader parent,
- URLStreamHandlerFactory factory)
- throws SecurityException
- {
- super(parent);
- this.securityContext = null;
- this.factory = factory;
- // If this factory is not yet in factoryCache, add it.
- factoryCache.add(factory);
- addURLs(urls);
- }
-
- // 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;
-
- // Create a loader for this URL.
- URLLoader loader = null;
- String file = newUrl.getFile();
- String protocol = newUrl.getProtocol();
-
- // If we have a file: URL, we want to make it absolute
- // here, before we decide whether it is really a jar.
- URL absoluteURL;
- if ("file".equals (protocol))
- {
- File dir = new File(file);
- try
- {
- absoluteURL = dir.getCanonicalFile().toURL();
- }
- catch (IOException ignore)
- {
- try
- {
- absoluteURL = dir.getAbsoluteFile().toURL();
- }
- catch (MalformedURLException _)
- {
- // This really should not happen.
- absoluteURL = newUrl;
- }
- }
- }
- else
- {
- // This doesn't hurt, and it simplifies the logic a
- // little.
- absoluteURL = newUrl;
- }
-
- // First see if we can find a handler with the correct name.
- try
- {
- Class> handler = Class.forName(URL_LOADER_PREFIX + protocol);
- Class>[] argTypes = new Class>[] { URLClassLoader.class,
- URLStreamHandlerCache.class,
- URLStreamHandlerFactory.class,
- URL.class,
- URL.class };
- Constructor k = handler.getDeclaredConstructor(argTypes);
- loader
- = (URLLoader) k.newInstance(new Object[] { this,
- factoryCache,
- factory,
- newUrl,
- absoluteURL });
- }
- catch (ClassNotFoundException ignore)
- {
- // Fall through.
- }
- catch (NoSuchMethodException nsme)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("couldn't find URLLoader constructor");
- vme.initCause(nsme);
- throw vme;
- }
- catch (InstantiationException inste)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("couldn't instantiate URLLoader");
- vme.initCause(inste);
- throw vme;
- }
- catch (InvocationTargetException ite)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("error instantiating URLLoader");
- vme.initCause(ite);
- throw vme;
- }
- catch (IllegalAccessException illae)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("invalid access to URLLoader");
- vme.initCause(illae);
- throw vme;
- }
-
- if (loader == null)
- {
- // If it is not a directory, use the jar loader.
- if (! (file.endsWith("/") || file.endsWith(File.separator)))
- loader = new JarURLLoader(this, factoryCache, factory,
- newUrl, absoluteURL);
- else if ("file".equals(protocol))
- loader = new FileURLLoader(this, factoryCache, factory,
- newUrl, absoluteURL);
- else
- loader = new RemoteURLLoader(this, factoryCache, factory,
- newUrl);
- }
-
- urlinfos.add(loader);
- ArrayListSecureClassLoader.getPermissions() 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 URL 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(CodeSource)
- */
- 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 URLClassLoader that gets
- * classes from the supplied URLs. 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 URLs
- */
- public static URLClassLoader newInstance(URL[] urls)
- throws SecurityException
- {
- return newInstance(urls, null);
- }
-
- /**
- * Creates a new instance of a URLClassLoader that gets
- * classes from the supplied URLs 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 URLs
- */
- 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 =
- AccessController.doPrivileged(new PrivilegedAction