|  | /* | 
|  | * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. | 
|  | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|  | * | 
|  | * This code is free software; you can redistribute it and/or modify it | 
|  | * under the terms of the GNU General Public License version 2 only, as | 
|  | * published by the Free Software Foundation.  Oracle designates this | 
|  | * particular file as subject to the "Classpath" exception as provided | 
|  | * by Oracle in the LICENSE file that accompanied this code. | 
|  | * | 
|  | * This code 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 | 
|  | * version 2 for more details (a copy is included in the LICENSE file that | 
|  | * accompanied this code). | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License version | 
|  | * 2 along with this work; if not, write to the Free Software Foundation, | 
|  | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|  | * | 
|  | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|  | * or visit www.oracle.com if you need additional information or have any | 
|  | * questions. | 
|  | */ | 
|  |  | 
|  | package java.net; | 
|  |  | 
|  | import java.lang.reflect.Method; | 
|  | import java.lang.reflect.Modifier; | 
|  | import java.lang.ref.*; | 
|  | import java.io.*; | 
|  | import java.net.URL; | 
|  | import java.net.URLConnection; | 
|  | import java.net.URLStreamHandlerFactory; | 
|  | import java.util.Enumeration; | 
|  | import java.util.*; | 
|  | import java.util.jar.Manifest; | 
|  | import java.util.jar.JarFile; | 
|  | import java.util.jar.Attributes; | 
|  | import java.util.jar.Attributes.Name; | 
|  | import java.security.CodeSigner; | 
|  | import java.security.PrivilegedAction; | 
|  | import java.security.PrivilegedExceptionAction; | 
|  | import java.security.AccessController; | 
|  | import java.security.AccessControlContext; | 
|  | import java.security.SecureClassLoader; | 
|  | import java.security.CodeSource; | 
|  | import java.security.Permission; | 
|  | import java.security.PermissionCollection; | 
|  | import sun.misc.Resource; | 
|  | import sun.misc.URLClassPath; | 
|  | import sun.net.www.ParseUtil; | 
|  | import sun.security.util.SecurityConstants; | 
|  |  | 
|  | /** | 
|  | * This class loader is used to load classes and resources from a search | 
|  | * path of URLs referring to both JAR files and directories. Any URL that | 
|  | * ends with a '/' is assumed to refer to a directory. Otherwise, the URL | 
|  | * is assumed to refer to a JAR file which will be opened as needed. | 
|  | * <p> | 
|  | * The AccessControlContext of the thread that created the instance of | 
|  | * URLClassLoader will be used when subsequently loading classes and | 
|  | * resources. | 
|  | * <p> | 
|  | * The classes that are loaded are by default granted permission only to | 
|  | * access the URLs specified when the URLClassLoader was created. | 
|  | * | 
|  | * @author  David Connelly | 
|  | * @since   1.2 | 
|  | */ | 
|  | public class URLClassLoader extends SecureClassLoader implements Closeable { | 
|  | /* The search path for classes and resources */ | 
|  | private final URLClassPath ucp; | 
|  |  | 
|  | /* The context to be used when loading classes and resources */ | 
|  | private final AccessControlContext acc; | 
|  |  | 
|  | /** | 
|  | * Constructs a new URLClassLoader for the given URLs. The URLs will be | 
|  | * searched in the order specified for classes and resources after first | 
|  | * searching in the specified parent class loader. Any URL that ends with | 
|  | * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed | 
|  | * to refer to a JAR file which will be downloaded and opened as needed. | 
|  | * | 
|  | * <p>If there is a security manager, this method first | 
|  | * calls the security manager's {@code checkCreateClassLoader} method | 
|  | * to ensure creation of a class loader is allowed. | 
|  | * | 
|  | * @param urls the URLs from which to load classes and resources | 
|  | * @param parent the parent class loader for delegation | 
|  | * @exception  SecurityException  if a security manager exists and its | 
|  | *             {@code checkCreateClassLoader} method doesn't allow | 
|  | *             creation of a class loader. | 
|  | * @see SecurityManager#checkCreateClassLoader | 
|  | */ | 
|  | public URLClassLoader(URL[] urls, ClassLoader parent) { | 
|  | super(parent); | 
|  | // this is to make the stack depth consistent with 1.1 | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkCreateClassLoader(); | 
|  | } | 
|  | ucp = new URLClassPath(urls); | 
|  | this.acc = AccessController.getContext(); | 
|  | } | 
|  |  | 
|  | URLClassLoader(URL[] urls, ClassLoader parent, | 
|  | AccessControlContext acc) { | 
|  | super(parent); | 
|  | // this is to make the stack depth consistent with 1.1 | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkCreateClassLoader(); | 
|  | } | 
|  | ucp = new URLClassPath(urls); | 
|  | this.acc = acc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Constructs a new URLClassLoader for the specified URLs using the | 
|  | * default delegation parent <code>ClassLoader</code>. The URLs will | 
|  | * be searched in the order specified for classes and resources after | 
|  | * first searching in the parent class loader. Any URL that ends with | 
|  | * a '/' is assumed to refer to a directory. Otherwise, the URL is | 
|  | * assumed to refer to a JAR file which will be downloaded and opened | 
|  | * as needed. | 
|  | * | 
|  | * <p>If there is a security manager, this method first | 
|  | * calls the security manager's <code>checkCreateClassLoader</code> method | 
|  | * to ensure creation of a class loader is allowed. | 
|  | * | 
|  | * @param urls the URLs from which to load classes and resources | 
|  | * | 
|  | * @exception  SecurityException  if a security manager exists and its | 
|  | *             <code>checkCreateClassLoader</code> method doesn't allow | 
|  | *             creation of a class loader. | 
|  | * @see SecurityManager#checkCreateClassLoader | 
|  | */ | 
|  | public URLClassLoader(URL[] urls) { | 
|  | super(); | 
|  | // this is to make the stack depth consistent with 1.1 | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkCreateClassLoader(); | 
|  | } | 
|  | ucp = new URLClassPath(urls); | 
|  | this.acc = AccessController.getContext(); | 
|  | } | 
|  |  | 
|  | URLClassLoader(URL[] urls, AccessControlContext acc) { | 
|  | super(); | 
|  | // this is to make the stack depth consistent with 1.1 | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkCreateClassLoader(); | 
|  | } | 
|  | ucp = new URLClassPath(urls); | 
|  | this.acc = acc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Constructs a new URLClassLoader for the specified URLs, parent | 
|  | * class loader, and URLStreamHandlerFactory. The parent argument | 
|  | * will be used as the parent class loader for delegation. The | 
|  | * factory argument will be used as the stream handler factory to | 
|  | * obtain protocol handlers when creating new jar URLs. | 
|  | * | 
|  | * <p>If there is a security manager, this method first | 
|  | * calls the security manager's <code>checkCreateClassLoader</code> method | 
|  | * to ensure creation of a class loader is allowed. | 
|  | * | 
|  | * @param urls the URLs from which to load classes and resources | 
|  | * @param parent the parent class loader for delegation | 
|  | * @param factory the URLStreamHandlerFactory to use when creating URLs | 
|  | * | 
|  | * @exception  SecurityException  if a security manager exists and its | 
|  | *             <code>checkCreateClassLoader</code> method doesn't allow | 
|  | *             creation of a class loader. | 
|  | * @see SecurityManager#checkCreateClassLoader | 
|  | */ | 
|  | public URLClassLoader(URL[] urls, ClassLoader parent, | 
|  | URLStreamHandlerFactory factory) { | 
|  | super(parent); | 
|  | // this is to make the stack depth consistent with 1.1 | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkCreateClassLoader(); | 
|  | } | 
|  | ucp = new URLClassPath(urls, factory); | 
|  | acc = AccessController.getContext(); | 
|  | } | 
|  |  | 
|  | /* A map (used as a set) to keep track of closeable local resources | 
|  | * (either JarFiles or FileInputStreams). We don't care about | 
|  | * Http resources since they don't need to be closed. | 
|  | * | 
|  | * If the resource is coming from a jar file | 
|  | * we keep a (weak) reference to the JarFile object which can | 
|  | * be closed if URLClassLoader.close() called. Due to jar file | 
|  | * caching there will typically be only one JarFile object | 
|  | * per underlying jar file. | 
|  | * | 
|  | * For file resources, which is probably a less common situation | 
|  | * we have to keep a weak reference to each stream. | 
|  | */ | 
|  |  | 
|  | private WeakHashMap<Closeable,Void> | 
|  | closeables = new WeakHashMap<>(); | 
|  |  | 
|  | /** | 
|  | * Returns an input stream for reading the specified resource. | 
|  | * If this loader is closed, then any resources opened by this method | 
|  | * will be closed. | 
|  | * | 
|  | * <p> The search order is described in the documentation for {@link | 
|  | * #getResource(String)}.  </p> | 
|  | * | 
|  | * @param  name | 
|  | *         The resource name | 
|  | * | 
|  | * @return  An input stream for reading the resource, or <tt>null</tt> | 
|  | *          if the resource could not be found | 
|  | * | 
|  | * @since  1.7 | 
|  | */ | 
|  | public InputStream getResourceAsStream(String name) { | 
|  | URL url = getResource(name); | 
|  | try { | 
|  | if (url == null) { | 
|  | return null; | 
|  | } | 
|  | URLConnection urlc = url.openConnection(); | 
|  | InputStream is = urlc.getInputStream(); | 
|  | if (urlc instanceof JarURLConnection) { | 
|  | JarURLConnection juc = (JarURLConnection)urlc; | 
|  | JarFile jar = juc.getJarFile(); | 
|  | synchronized (closeables) { | 
|  | if (!closeables.containsKey(jar)) { | 
|  | closeables.put(jar, null); | 
|  | } | 
|  | } | 
|  | } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) { | 
|  | synchronized (closeables) { | 
|  | closeables.put(is, null); | 
|  | } | 
|  | } | 
|  | return is; | 
|  | } catch (IOException e) { | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Closes this URLClassLoader, so that it can no longer be used to load | 
|  | * new classes or resources that are defined by this loader. | 
|  | * Classes and resources defined by any of this loader's parents in the | 
|  | * delegation hierarchy are still accessible. Also, any classes or resources | 
|  | * that are already loaded, are still accessible. | 
|  | * <p> | 
|  | * In the case of jar: and file: URLs, it also closes any files | 
|  | * that were opened by it. If another thread is loading a | 
|  | * class when the {@code close} method is invoked, then the result of | 
|  | * that load is undefined. | 
|  | * <p> | 
|  | * The method makes a best effort attempt to close all opened files, | 
|  | * by catching {@link IOException}s internally. Unchecked exceptions | 
|  | * and errors are not caught. Calling close on an already closed | 
|  | * loader has no effect. | 
|  | * <p> | 
|  | * @throws IOException if closing any file opened by this class loader | 
|  | * resulted in an IOException. Any such exceptions are caught internally. | 
|  | * If only one is caught, then it is re-thrown. If more than one exception | 
|  | * is caught, then the second and following exceptions are added | 
|  | * as suppressed exceptions of the first one caught, which is then re-thrown. | 
|  | * | 
|  | * @throws SecurityException if a security manager is set, and it denies | 
|  | *   {@link RuntimePermission}<tt>("closeClassLoader")</tt> | 
|  | * | 
|  | * @since 1.7 | 
|  | */ | 
|  | public void close() throws IOException { | 
|  | SecurityManager security = System.getSecurityManager(); | 
|  | if (security != null) { | 
|  | security.checkPermission(new RuntimePermission("closeClassLoader")); | 
|  | } | 
|  | List<IOException> errors = ucp.closeLoaders(); | 
|  |  | 
|  | // now close any remaining streams. | 
|  |  | 
|  | synchronized (closeables) { | 
|  | Set<Closeable> keys = closeables.keySet(); | 
|  | for (Closeable c : keys) { | 
|  | try { | 
|  | c.close(); | 
|  | } catch (IOException ioex) { | 
|  | errors.add(ioex); | 
|  | } | 
|  | } | 
|  | closeables.clear(); | 
|  | } | 
|  |  | 
|  | if (errors.isEmpty()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | IOException firstex = errors.remove(0); | 
|  |  | 
|  | // Suppress any remaining exceptions | 
|  |  | 
|  | for (IOException error: errors) { | 
|  | firstex.addSuppressed(error); | 
|  | } | 
|  | throw firstex; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Appends the specified URL to the list of URLs to search for | 
|  | * classes and resources. | 
|  | * <p> | 
|  | * If the URL specified is <code>null</code> or is already in the | 
|  | * list of URLs, or if this loader is closed, then invoking this | 
|  | * method has no effect. | 
|  | * | 
|  | * @param url the URL to be added to the search path of URLs | 
|  | */ | 
|  | protected void addURL(URL url) { | 
|  | ucp.addURL(url); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the search path of URLs for loading classes and resources. | 
|  | * This includes the original list of URLs specified to the constructor, | 
|  | * along with any URLs subsequently appended by the addURL() method. | 
|  | * @return the search path of URLs for loading classes and resources. | 
|  | */ | 
|  | public URL[] getURLs() { | 
|  | return ucp.getURLs(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Finds and loads the class with the specified name from the URL search | 
|  | * path. Any URLs referring to JAR files are loaded and opened as needed | 
|  | * until the class is found. | 
|  | * | 
|  | * @param name the name of the class | 
|  | * @return the resulting class | 
|  | * @exception ClassNotFoundException if the class could not be found, | 
|  | *            or if the loader is closed. | 
|  | */ | 
|  | protected Class<?> findClass(final String name) | 
|  | throws ClassNotFoundException | 
|  | { | 
|  | try { | 
|  | return AccessController.doPrivileged( | 
|  | new PrivilegedExceptionAction<Class>() { | 
|  | public Class run() throws ClassNotFoundException { | 
|  | String path = name.replace('.', '/').concat(".class"); | 
|  | Resource res = ucp.getResource(path, false); | 
|  | if (res != null) { | 
|  | try { | 
|  | return defineClass(name, res); | 
|  | } catch (IOException e) { | 
|  | throw new ClassNotFoundException(name, e); | 
|  | } | 
|  | } else { | 
|  | throw new ClassNotFoundException(name); | 
|  | } | 
|  | } | 
|  | }, acc); | 
|  | } catch (java.security.PrivilegedActionException pae) { | 
|  | throw (ClassNotFoundException) pae.getException(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Retrieve the package using the specified package name. | 
|  | * If non-null, verify the package using the specified code | 
|  | * source and manifest. | 
|  | */ | 
|  | private Package getAndVerifyPackage(String pkgname, | 
|  | Manifest man, URL url) { | 
|  | Package pkg = getPackage(pkgname); | 
|  | if (pkg != null) { | 
|  | // Package found, so check package sealing. | 
|  | if (pkg.isSealed()) { | 
|  | // Verify that code source URL is the same. | 
|  | if (!pkg.isSealed(url)) { | 
|  | throw new SecurityException( | 
|  | "sealing violation: package " + pkgname + " is sealed"); | 
|  | } | 
|  | } else { | 
|  | // Make sure we are not attempting to seal the package | 
|  | // at this code source URL. | 
|  | if ((man != null) && isSealed(pkgname, man)) { | 
|  | throw new SecurityException( | 
|  | "sealing violation: can't seal package " + pkgname + | 
|  | ": already loaded"); | 
|  | } | 
|  | } | 
|  | } | 
|  | return pkg; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Defines a Class using the class bytes obtained from the specified | 
|  | * Resource. The resulting Class must be resolved before it can be | 
|  | * used. | 
|  | */ | 
|  | private Class defineClass(String name, Resource res) throws IOException { | 
|  | long t0 = System.nanoTime(); | 
|  | int i = name.lastIndexOf('.'); | 
|  | URL url = res.getCodeSourceURL(); | 
|  | if (i != -1) { | 
|  | String pkgname = name.substring(0, i); | 
|  | // Check if package already loaded. | 
|  | Manifest man = res.getManifest(); | 
|  | if (getAndVerifyPackage(pkgname, man, url) == null) { | 
|  | try { | 
|  | if (man != null) { | 
|  | definePackage(pkgname, man, url); | 
|  | } else { | 
|  | definePackage(pkgname, null, null, null, null, null, null, null); | 
|  | } | 
|  | } catch (IllegalArgumentException iae) { | 
|  | // parallel-capable class loaders: re-verify in case of a | 
|  | // race condition | 
|  | if (getAndVerifyPackage(pkgname, man, url) == null) { | 
|  | // Should never happen | 
|  | throw new AssertionError("Cannot find package " + | 
|  | pkgname); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | // Now read the class bytes and define the class | 
|  | java.nio.ByteBuffer bb = res.getByteBuffer(); | 
|  | if (bb != null) { | 
|  | // Use (direct) ByteBuffer: | 
|  | CodeSigner[] signers = res.getCodeSigners(); | 
|  | CodeSource cs = new CodeSource(url, signers); | 
|  | return defineClass(name, bb, cs); | 
|  | } else { | 
|  | byte[] b = res.getBytes(); | 
|  | // must read certificates AFTER reading bytes. | 
|  | CodeSigner[] signers = res.getCodeSigners(); | 
|  | CodeSource cs = new CodeSource(url, signers); | 
|  | return defineClass(name, b, 0, b.length, cs); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Defines a new package by name in this ClassLoader. The attributes | 
|  | * contained in the specified Manifest will be used to obtain package | 
|  | * version and sealing information. For sealed packages, the additional | 
|  | * URL specifies the code source URL from which the package was loaded. | 
|  | * | 
|  | * @param name  the package name | 
|  | * @param man   the Manifest containing package version and sealing | 
|  | *              information | 
|  | * @param url   the code source url for the package, or null if none | 
|  | * @exception   IllegalArgumentException if the package name duplicates | 
|  | *              an existing package either in this class loader or one | 
|  | *              of its ancestors | 
|  | * @return the newly defined Package object | 
|  | */ | 
|  | protected Package definePackage(String name, Manifest man, URL url) | 
|  | throws IllegalArgumentException | 
|  | { | 
|  | String path = name.replace('.', '/').concat("/"); | 
|  | String specTitle = null, specVersion = null, specVendor = null; | 
|  | String implTitle = null, implVersion = null, implVendor = null; | 
|  | String sealed = null; | 
|  | URL sealBase = null; | 
|  |  | 
|  | Attributes attr = man.getAttributes(path); | 
|  | if (attr != null) { | 
|  | specTitle   = attr.getValue(Name.SPECIFICATION_TITLE); | 
|  | specVersion = attr.getValue(Name.SPECIFICATION_VERSION); | 
|  | specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR); | 
|  | implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE); | 
|  | implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); | 
|  | implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR); | 
|  | sealed      = attr.getValue(Name.SEALED); | 
|  | } | 
|  | attr = man.getMainAttributes(); | 
|  | if (attr != null) { | 
|  | if (specTitle == null) { | 
|  | specTitle = attr.getValue(Name.SPECIFICATION_TITLE); | 
|  | } | 
|  | if (specVersion == null) { | 
|  | specVersion = attr.getValue(Name.SPECIFICATION_VERSION); | 
|  | } | 
|  | if (specVendor == null) { | 
|  | specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); | 
|  | } | 
|  | if (implTitle == null) { | 
|  | implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); | 
|  | } | 
|  | if (implVersion == null) { | 
|  | implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); | 
|  | } | 
|  | if (implVendor == null) { | 
|  | implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); | 
|  | } | 
|  | if (sealed == null) { | 
|  | sealed = attr.getValue(Name.SEALED); | 
|  | } | 
|  | } | 
|  | if ("true".equalsIgnoreCase(sealed)) { | 
|  | sealBase = url; | 
|  | } | 
|  | return definePackage(name, specTitle, specVersion, specVendor, | 
|  | implTitle, implVersion, implVendor, sealBase); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Returns true if the specified package name is sealed according to the | 
|  | * given manifest. | 
|  | */ | 
|  | private boolean isSealed(String name, Manifest man) { | 
|  | String path = name.replace('.', '/').concat("/"); | 
|  | Attributes attr = man.getAttributes(path); | 
|  | String sealed = null; | 
|  | if (attr != null) { | 
|  | sealed = attr.getValue(Name.SEALED); | 
|  | } | 
|  | if (sealed == null) { | 
|  | if ((attr = man.getMainAttributes()) != null) { | 
|  | sealed = attr.getValue(Name.SEALED); | 
|  | } | 
|  | } | 
|  | return "true".equalsIgnoreCase(sealed); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Finds the resource with the specified name on the URL search path. | 
|  | * | 
|  | * @param name the name of the resource | 
|  | * @return a <code>URL</code> for the resource, or <code>null</code> | 
|  | * if the resource could not be found, or if the loader is closed. | 
|  | */ | 
|  | public URL findResource(final String name) { | 
|  | /* | 
|  | * The same restriction to finding classes applies to resources | 
|  | */ | 
|  | URL url = AccessController.doPrivileged( | 
|  | new PrivilegedAction<URL>() { | 
|  | public URL run() { | 
|  | return ucp.findResource(name, true); | 
|  | } | 
|  | }, acc); | 
|  |  | 
|  | return url != null ? ucp.checkURL(url) : null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns an Enumeration of URLs representing all of the resources | 
|  | * on the URL search path having the specified name. | 
|  | * | 
|  | * @param name the resource name | 
|  | * @exception IOException if an I/O exception occurs | 
|  | * @return an <code>Enumeration</code> of <code>URL</code>s | 
|  | *         If the loader is closed, the Enumeration will be empty. | 
|  | */ | 
|  | public Enumeration<URL> findResources(final String name) | 
|  | throws IOException | 
|  | { | 
|  | final Enumeration<URL> e = ucp.findResources(name, true); | 
|  |  | 
|  | return new Enumeration<URL>() { | 
|  | private URL url = null; | 
|  |  | 
|  | private boolean next() { | 
|  | if (url != null) { | 
|  | return true; | 
|  | } | 
|  | do { | 
|  | URL u = AccessController.doPrivileged( | 
|  | new PrivilegedAction<URL>() { | 
|  | public URL run() { | 
|  | if (!e.hasMoreElements()) | 
|  | return null; | 
|  | return e.nextElement(); | 
|  | } | 
|  | }, acc); | 
|  | if (u == null) | 
|  | break; | 
|  | url = ucp.checkURL(u); | 
|  | } while (url == null); | 
|  | return url != null; | 
|  | } | 
|  |  | 
|  | public URL nextElement() { | 
|  | if (!next()) { | 
|  | throw new NoSuchElementException(); | 
|  | } | 
|  | URL u = url; | 
|  | url = null; | 
|  | return u; | 
|  | } | 
|  |  | 
|  | public boolean hasMoreElements() { | 
|  | return next(); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the permissions for the given codesource object. | 
|  | * The implementation of this method first calls super.getPermissions | 
|  | * and then adds permissions based on the URL of the codesource. | 
|  | * <p> | 
|  | * If the protocol of this URL is "jar", then the permission granted | 
|  | * is based on the permission that is required by the URL of the Jar | 
|  | * file. | 
|  | * <p> | 
|  | * If the protocol is "file" and there is an authority component, then | 
|  | * permission to connect to and accept connections from that authority | 
|  | * may be granted. If the protocol is "file" | 
|  | * and the path specifies a file, then permission to read that | 
|  | * file is granted. If protocol is "file" and the path is | 
|  | * a directory, permission is granted to read all files | 
|  | * and (recursively) all files and subdirectories contained in | 
|  | * that directory. | 
|  | * <p> | 
|  | * If the protocol is not "file", then permission | 
|  | * to connect to and accept connections from the URL's host is granted. | 
|  | * @param codesource the codesource | 
|  | * @return the permissions granted to the codesource | 
|  | */ | 
|  | protected PermissionCollection getPermissions(CodeSource codesource) | 
|  | { | 
|  | PermissionCollection perms = super.getPermissions(codesource); | 
|  |  | 
|  | URL url = codesource.getLocation(); | 
|  |  | 
|  | Permission p; | 
|  | URLConnection urlConnection; | 
|  |  | 
|  | try { | 
|  | urlConnection = url.openConnection(); | 
|  | p = urlConnection.getPermission(); | 
|  | } catch (java.io.IOException ioe) { | 
|  | p = null; | 
|  | urlConnection = null; | 
|  | } | 
|  |  | 
|  | if (p instanceof FilePermission) { | 
|  | // if the permission has a separator char on the end, | 
|  | // it means the codebase is a directory, and we need | 
|  | // to add an additional permission to read recursively | 
|  | String path = p.getName(); | 
|  | if (path.endsWith(File.separator)) { | 
|  | path += "-"; | 
|  | p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); | 
|  | } | 
|  | } else if ((p == null) && (url.getProtocol().equals("file"))) { | 
|  | String path = url.getFile().replace('/', File.separatorChar); | 
|  | path = ParseUtil.decode(path); | 
|  | if (path.endsWith(File.separator)) | 
|  | path += "-"; | 
|  | p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION); | 
|  | } else { | 
|  | /** | 
|  | * Not loading from a 'file:' URL so we want to give the class | 
|  | * permission to connect to and accept from the remote host | 
|  | * after we've made sure the host is the correct one and is valid. | 
|  | */ | 
|  | URL locUrl = url; | 
|  | if (urlConnection instanceof JarURLConnection) { | 
|  | locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); | 
|  | } | 
|  | String host = locUrl.getHost(); | 
|  | if (host != null && (host.length() > 0)) | 
|  | p = new SocketPermission(host, | 
|  | SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); | 
|  | } | 
|  |  | 
|  | // make sure the person that created this class loader | 
|  | // would have this permission | 
|  |  | 
|  | if (p != null) { | 
|  | final SecurityManager sm = System.getSecurityManager(); | 
|  | if (sm != null) { | 
|  | final Permission fp = p; | 
|  | AccessController.doPrivileged(new PrivilegedAction<Void>() { | 
|  | public Void run() throws SecurityException { | 
|  | sm.checkPermission(fp); | 
|  | return null; | 
|  | } | 
|  | }, acc); | 
|  | } | 
|  | perms.add(p); | 
|  | } | 
|  | return perms; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a new instance of URLClassLoader for the specified | 
|  | * URLs and parent class loader. If a security manager is | 
|  | * installed, the <code>loadClass</code> method of the URLClassLoader | 
|  | * returned by this method will invoke the | 
|  | * <code>SecurityManager.checkPackageAccess</code> method before | 
|  | * loading the class. | 
|  | * | 
|  | * @param urls the URLs to search for classes and resources | 
|  | * @param parent the parent class loader for delegation | 
|  | * @return the resulting class loader | 
|  | */ | 
|  | public static URLClassLoader newInstance(final URL[] urls, | 
|  | final ClassLoader parent) { | 
|  | // Save the caller's context | 
|  | final AccessControlContext acc = AccessController.getContext(); | 
|  | // Need a privileged block to create the class loader | 
|  | URLClassLoader ucl = AccessController.doPrivileged( | 
|  | new PrivilegedAction<URLClassLoader>() { | 
|  | public URLClassLoader run() { | 
|  | return new FactoryURLClassLoader(urls, parent, acc); | 
|  | } | 
|  | }); | 
|  | return ucl; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a new instance of URLClassLoader for the specified | 
|  | * URLs and default parent class loader. If a security manager is | 
|  | * installed, the <code>loadClass</code> method of the URLClassLoader | 
|  | * returned by this method will invoke the | 
|  | * <code>SecurityManager.checkPackageAccess</code> before | 
|  | * loading the class. | 
|  | * | 
|  | * @param urls the URLs to search for classes and resources | 
|  | * @return the resulting class loader | 
|  | */ | 
|  | public static URLClassLoader newInstance(final URL[] urls) { | 
|  | // Save the caller's context | 
|  | final AccessControlContext acc = AccessController.getContext(); | 
|  | // Need a privileged block to create the class loader | 
|  | URLClassLoader ucl = AccessController.doPrivileged( | 
|  | new PrivilegedAction<URLClassLoader>() { | 
|  | public URLClassLoader run() { | 
|  | return new FactoryURLClassLoader(urls, acc); | 
|  | } | 
|  | }); | 
|  | return ucl; | 
|  | } | 
|  |  | 
|  | static { | 
|  | /*sun.misc.SharedSecrets.setJavaNetAccess ( | 
|  | new sun.misc.JavaNetAccess() { | 
|  | public URLClassPath getURLClassPath (URLClassLoader u) { | 
|  | return u.ucp; | 
|  | } | 
|  | } | 
|  | );*/ | 
|  | ClassLoader.registerAsParallelCapable(); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class FactoryURLClassLoader extends URLClassLoader { | 
|  |  | 
|  | static { | 
|  | ClassLoader.registerAsParallelCapable(); | 
|  | } | 
|  |  | 
|  | FactoryURLClassLoader(URL[] urls, ClassLoader parent, | 
|  | AccessControlContext acc) { | 
|  | super(urls, parent, acc); | 
|  | } | 
|  |  | 
|  | FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { | 
|  | super(urls, acc); | 
|  | } | 
|  |  | 
|  | public final Class loadClass(String name, boolean resolve) | 
|  | throws ClassNotFoundException | 
|  | { | 
|  | // First check if we have permission to access the package. This | 
|  | // should go away once we've added support for exported packages. | 
|  | SecurityManager sm = System.getSecurityManager(); | 
|  | if (sm != null) { | 
|  | int i = name.lastIndexOf('.'); | 
|  | if (i != -1) { | 
|  | sm.checkPackageAccess(name.substring(0, i)); | 
|  | } | 
|  | } | 
|  | return super.loadClass(name, resolve); | 
|  | } | 
|  | } |