1 /*
   2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.net;
  27 
  28 import java.io.Closeable;
  29 import java.io.File;
  30 import java.io.FilePermission;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.security.AccessControlContext;
  34 import java.security.AccessController;
  35 import java.security.CodeSigner;
  36 import java.security.CodeSource;
  37 import java.security.Permission;
  38 import java.security.PermissionCollection;
  39 import java.security.PrivilegedAction;
  40 import java.security.PrivilegedExceptionAction;
  41 import java.security.SecureClassLoader;
  42 import java.util.Enumeration;
  43 import java.util.List;
  44 import java.util.NoSuchElementException;
  45 import java.util.Objects;
  46 import java.util.Set;
  47 import java.util.WeakHashMap;
  48 import java.util.jar.Attributes;
  49 import java.util.jar.Attributes.Name;
  50 import java.util.jar.JarFile;
  51 import java.util.jar.Manifest;
  52 
  53 import jdk.internal.loader.Resource;
  54 import jdk.internal.loader.URLClassPath;
  55 import jdk.internal.misc.JavaNetURLClassLoaderAccess;
  56 import jdk.internal.misc.SharedSecrets;
  57 import jdk.internal.perf.PerfCounter;
  58 import sun.net.www.ParseUtil;
  59 import sun.security.util.SecurityConstants;
  60 
  61 /**
  62  * This class loader is used to load classes and resources from a search
  63  * path of URLs referring to both JAR files and directories. Any {@code jar:}
  64  * scheme URL (see {@link java.net.JarURLConnection}) is assumed to refer to a
  65  * JAR file.  Any {@code file:} scheme URL that ends with a '/' is assumed to
  66  * refer to a directory. Otherwise, the URL is assumed to refer to a JAR file
  67  * which will be opened as needed.
  68  * <p>
  69  * This class loader supports the loading of classes and resources from the
  70  * contents of a <a href="../util/jar/JarFile.html#multirelease">multi-release</a>
  71  * JAR file that is referred to by a given URL.
  72  * <p>
  73  * The AccessControlContext of the thread that created the instance of
  74  * URLClassLoader will be used when subsequently loading classes and
  75  * resources.
  76  * <p>
  77  * The classes that are loaded are by default granted permission only to
  78  * access the URLs specified when the URLClassLoader was created.
  79  *
  80  * @author  David Connelly
  81  * @since   1.2
  82  */
  83 public class URLClassLoader extends SecureClassLoader implements Closeable {
  84     /* The search path for classes and resources */
  85     private final URLClassPath ucp;
  86 
  87     /* The context to be used when loading classes and resources */
  88     private final AccessControlContext acc;
  89 
  90     /**
  91      * Constructs a new URLClassLoader for the given URLs. The URLs will be
  92      * searched in the order specified for classes and resources after first
  93      * searching in the specified parent class loader.  Any {@code jar:}
  94      * scheme URL is assumed to refer to a JAR file.  Any {@code file:} scheme
  95      * URL that ends with a '/' is assumed to refer to a directory.  Otherwise,
  96      * the URL is assumed to refer to a JAR file which will be downloaded and
  97      * opened as needed.
  98      *
  99      * <p>If there is a security manager, this method first
 100      * calls the security manager's {@code checkCreateClassLoader} method
 101      * to ensure creation of a class loader is allowed.
 102      *
 103      * @param urls the URLs from which to load classes and resources
 104      * @param parent the parent class loader for delegation
 105      * @exception  SecurityException  if a security manager exists and its
 106      *             {@code checkCreateClassLoader} method doesn't allow
 107      *             creation of a class loader.
 108      * @exception  NullPointerException if {@code urls} is {@code null}.
 109      * @see SecurityManager#checkCreateClassLoader
 110      */
 111     public URLClassLoader(URL[] urls, ClassLoader parent) {
 112         super(parent);
 113         // this is to make the stack depth consistent with 1.1
 114         SecurityManager security = System.getSecurityManager();
 115         if (security != null) {
 116             security.checkCreateClassLoader();
 117         }
 118         this.acc = AccessController.getContext();
 119         this.ucp = new URLClassPath(urls, acc);
 120     }
 121 
 122     URLClassLoader(String name, URL[] urls, ClassLoader parent,
 123                    AccessControlContext acc) {
 124         super(name, parent);
 125         // this is to make the stack depth consistent with 1.1
 126         SecurityManager security = System.getSecurityManager();
 127         if (security != null) {
 128             security.checkCreateClassLoader();
 129         }
 130         this.acc = acc;
 131         this.ucp = new URLClassPath(urls, acc);
 132     }
 133 
 134     /**
 135      * Constructs a new URLClassLoader for the specified URLs using the
 136      * default delegation parent {@code ClassLoader}. The URLs will
 137      * be searched in the order specified for classes and resources after
 138      * first searching in the parent class loader. Any URL that ends with
 139      * a '/' is assumed to refer to a directory. Otherwise, the URL is
 140      * assumed to refer to a JAR file which will be downloaded and opened
 141      * as needed.
 142      *
 143      * <p>If there is a security manager, this method first
 144      * calls the security manager's {@code checkCreateClassLoader} method
 145      * to ensure creation of a class loader is allowed.
 146      *
 147      * @param urls the URLs from which to load classes and resources
 148      *
 149      * @exception  SecurityException  if a security manager exists and its
 150      *             {@code checkCreateClassLoader} method doesn't allow
 151      *             creation of a class loader.
 152      * @exception  NullPointerException if {@code urls} is {@code null}.
 153      * @see SecurityManager#checkCreateClassLoader
 154      */
 155     public URLClassLoader(URL[] urls) {
 156         super();
 157         // this is to make the stack depth consistent with 1.1
 158         SecurityManager security = System.getSecurityManager();
 159         if (security != null) {
 160             security.checkCreateClassLoader();
 161         }
 162         this.acc = AccessController.getContext();
 163         this.ucp = new URLClassPath(urls, acc);
 164     }
 165 
 166     URLClassLoader(URL[] urls, AccessControlContext acc) {
 167         super();
 168         // this is to make the stack depth consistent with 1.1
 169         SecurityManager security = System.getSecurityManager();
 170         if (security != null) {
 171             security.checkCreateClassLoader();
 172         }
 173         this.acc = acc;
 174         this.ucp = new URLClassPath(urls, acc);
 175     }
 176 
 177     /**
 178      * Constructs a new URLClassLoader for the specified URLs, parent
 179      * class loader, and URLStreamHandlerFactory. The parent argument
 180      * will be used as the parent class loader for delegation. The
 181      * factory argument will be used as the stream handler factory to
 182      * obtain protocol handlers when creating new jar URLs.
 183      *
 184      * <p>If there is a security manager, this method first
 185      * calls the security manager's {@code checkCreateClassLoader} method
 186      * to ensure creation of a class loader is allowed.
 187      *
 188      * @param urls the URLs from which to load classes and resources
 189      * @param parent the parent class loader for delegation
 190      * @param factory the URLStreamHandlerFactory to use when creating URLs
 191      *
 192      * @exception  SecurityException  if a security manager exists and its
 193      *             {@code checkCreateClassLoader} method doesn't allow
 194      *             creation of a class loader.
 195      * @exception  NullPointerException if {@code urls} is {@code null}.
 196      * @see SecurityManager#checkCreateClassLoader
 197      */
 198     public URLClassLoader(URL[] urls, ClassLoader parent,
 199                           URLStreamHandlerFactory factory) {
 200         super(parent);
 201         // this is to make the stack depth consistent with 1.1
 202         SecurityManager security = System.getSecurityManager();
 203         if (security != null) {
 204             security.checkCreateClassLoader();
 205         }
 206         this.acc = AccessController.getContext();
 207         this.ucp = new URLClassPath(urls, factory, acc);
 208     }
 209 
 210 
 211     /**
 212      * Constructs a new named {@code URLClassLoader} for the specified URLs.
 213      * The URLs will be searched in the order specified for classes
 214      * and resources after first searching in the specified parent class loader.
 215      * Any URL that ends with a '/' is assumed to refer to a directory.
 216      * Otherwise, the URL is assumed to refer to a JAR file which will be
 217      * downloaded and opened as needed.
 218      *
 219      * @param  name class loader name; or {@code null} if not named
 220      * @param  urls the URLs from which to load classes and resources
 221      * @param  parent the parent class loader for delegation
 222      *
 223      * @throws IllegalArgumentException if the given name is empty.
 224      * @throws NullPointerException if {@code urls} is {@code null}.
 225      *
 226      * @throws SecurityException if a security manager exists and its
 227      *         {@link SecurityManager#checkCreateClassLoader()} method doesn't
 228      *         allow creation of a class loader.
 229      *
 230      * @since 9
 231      */
 232     public URLClassLoader(String name,
 233                           URL[] urls,
 234                           ClassLoader parent) {
 235         super(name, parent);
 236         // this is to make the stack depth consistent with 1.1
 237         SecurityManager security = System.getSecurityManager();
 238         if (security != null) {
 239             security.checkCreateClassLoader();
 240         }
 241         this.acc = AccessController.getContext();
 242         this.ucp = new URLClassPath(urls, acc);
 243     }
 244 
 245     /**
 246      * Constructs a new named {@code URLClassLoader} for the specified URLs,
 247      * parent class loader, and URLStreamHandlerFactory.
 248      * The parent argument will be used as the parent class loader for delegation.
 249      * The factory argument will be used as the stream handler factory to
 250      * obtain protocol handlers when creating new jar URLs.
 251      *
 252      * @param  name class loader name; or {@code null} if not named
 253      * @param  urls the URLs from which to load classes and resources
 254      * @param  parent the parent class loader for delegation
 255      * @param  factory the URLStreamHandlerFactory to use when creating URLs
 256      *
 257      * @throws IllegalArgumentException if the given name is empty.
 258      * @throws NullPointerException if {@code urls} is {@code null}.
 259      *
 260      * @throws SecurityException if a security manager exists and its
 261      *         {@code checkCreateClassLoader} method doesn't allow
 262      *         creation of a class loader.
 263      *
 264      * @since 9
 265      */
 266     public URLClassLoader(String name, URL[] urls, ClassLoader parent,
 267                           URLStreamHandlerFactory factory) {
 268         super(name, parent);
 269         // this is to make the stack depth consistent with 1.1
 270         SecurityManager security = System.getSecurityManager();
 271         if (security != null) {
 272             security.checkCreateClassLoader();
 273         }
 274         this.acc = AccessController.getContext();
 275         this.ucp = new URLClassPath(urls, factory, acc);
 276     }
 277 
 278     /* A map (used as a set) to keep track of closeable local resources
 279      * (either JarFiles or FileInputStreams). We don't care about
 280      * Http resources since they don't need to be closed.
 281      *
 282      * If the resource is coming from a jar file
 283      * we keep a (weak) reference to the JarFile object which can
 284      * be closed if URLClassLoader.close() called. Due to jar file
 285      * caching there will typically be only one JarFile object
 286      * per underlying jar file.
 287      *
 288      * For file resources, which is probably a less common situation
 289      * we have to keep a weak reference to each stream.
 290      */
 291 
 292     private WeakHashMap<Closeable,Void>
 293         closeables = new WeakHashMap<>();
 294 
 295     /**
 296      * Returns an input stream for reading the specified resource.
 297      * If this loader is closed, then any resources opened by this method
 298      * will be closed.
 299      *
 300      * <p> The search order is described in the documentation for {@link
 301      * #getResource(String)}.  </p>
 302      *
 303      * @param  name
 304      *         The resource name
 305      *
 306      * @return  An input stream for reading the resource, or {@code null}
 307      *          if the resource could not be found
 308      *
 309      * @throws  NullPointerException If {@code name} is {@code null}
 310      *
 311      * @since  1.7
 312      */
 313     public InputStream getResourceAsStream(String name) {
 314         Objects.requireNonNull(name);
 315         URL url = getResource(name);
 316         try {
 317             if (url == null) {
 318                 return null;
 319             }
 320             URLConnection urlc = url.openConnection();
 321             InputStream is = urlc.getInputStream();
 322             if (urlc instanceof JarURLConnection) {
 323                 JarURLConnection juc = (JarURLConnection)urlc;
 324                 JarFile jar = juc.getJarFile();
 325                 synchronized (closeables) {
 326                     if (!closeables.containsKey(jar)) {
 327                         closeables.put(jar, null);
 328                     }
 329                 }
 330             } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
 331                 synchronized (closeables) {
 332                     closeables.put(is, null);
 333                 }
 334             }
 335             return is;
 336         } catch (IOException e) {
 337             return null;
 338         }
 339     }
 340 
 341    /**
 342     * Closes this URLClassLoader, so that it can no longer be used to load
 343     * new classes or resources that are defined by this loader.
 344     * Classes and resources defined by any of this loader's parents in the
 345     * delegation hierarchy are still accessible. Also, any classes or resources
 346     * that are already loaded, are still accessible.
 347     * <p>
 348     * In the case of jar: and file: URLs, it also closes any files
 349     * that were opened by it. If another thread is loading a
 350     * class when the {@code close} method is invoked, then the result of
 351     * that load is undefined.
 352     * <p>
 353     * The method makes a best effort attempt to close all opened files,
 354     * by catching {@link IOException}s internally. Unchecked exceptions
 355     * and errors are not caught. Calling close on an already closed
 356     * loader has no effect.
 357     *
 358     * @exception IOException if closing any file opened by this class loader
 359     * resulted in an IOException. Any such exceptions are caught internally.
 360     * If only one is caught, then it is re-thrown. If more than one exception
 361     * is caught, then the second and following exceptions are added
 362     * as suppressed exceptions of the first one caught, which is then re-thrown.
 363     *
 364     * @exception SecurityException if a security manager is set, and it denies
 365     *   {@link RuntimePermission}{@code ("closeClassLoader")}
 366     *
 367     * @since 1.7
 368     */
 369     public void close() throws IOException {
 370         SecurityManager security = System.getSecurityManager();
 371         if (security != null) {
 372             security.checkPermission(new RuntimePermission("closeClassLoader"));
 373         }
 374         List<IOException> errors = ucp.closeLoaders();
 375 
 376         // now close any remaining streams.
 377 
 378         synchronized (closeables) {
 379             Set<Closeable> keys = closeables.keySet();
 380             for (Closeable c : keys) {
 381                 try {
 382                     c.close();
 383                 } catch (IOException ioex) {
 384                     errors.add(ioex);
 385                 }
 386             }
 387             closeables.clear();
 388         }
 389 
 390         if (errors.isEmpty()) {
 391             return;
 392         }
 393 
 394         IOException firstex = errors.remove(0);
 395 
 396         // Suppress any remaining exceptions
 397 
 398         for (IOException error: errors) {
 399             firstex.addSuppressed(error);
 400         }
 401         throw firstex;
 402     }
 403 
 404     /**
 405      * Appends the specified URL to the list of URLs to search for
 406      * classes and resources.
 407      * <p>
 408      * If the URL specified is {@code null} or is already in the
 409      * list of URLs, or if this loader is closed, then invoking this
 410      * method has no effect.
 411      *
 412      * @param url the URL to be added to the search path of URLs
 413      */
 414     protected void addURL(URL url) {
 415         ucp.addURL(url);
 416     }
 417 
 418     /**
 419      * Returns the search path of URLs for loading classes and resources.
 420      * This includes the original list of URLs specified to the constructor,
 421      * along with any URLs subsequently appended by the addURL() method.
 422      * @return the search path of URLs for loading classes and resources.
 423      */
 424     public URL[] getURLs() {
 425         return ucp.getURLs();
 426     }
 427 
 428     /**
 429      * Finds and loads the class with the specified name from the URL search
 430      * path. Any URLs referring to JAR files are loaded and opened as needed
 431      * until the class is found.
 432      *
 433      * @param name the name of the class
 434      * @return the resulting class
 435      * @exception ClassNotFoundException if the class could not be found,
 436      *            or if the loader is closed.
 437      * @exception NullPointerException if {@code name} is {@code null}.
 438      */
 439     protected Class<?> findClass(final String name)
 440         throws ClassNotFoundException
 441     {
 442         final Class<?> result;
 443         try {
 444             result = AccessController.doPrivileged(
 445                 new PrivilegedExceptionAction<>() {
 446                     public Class<?> run() throws ClassNotFoundException {
 447                         String path = name.replace('.', '/').concat(".class");
 448                         Resource res = ucp.getResource(path, false);
 449                         if (res != null) {
 450                             try {
 451                                 return defineClass(name, res);
 452                             } catch (IOException e) {
 453                                 throw new ClassNotFoundException(name, e);
 454                             }
 455                         } else {
 456                             return null;
 457                         }
 458                     }
 459                 }, acc);
 460         } catch (java.security.PrivilegedActionException pae) {
 461             throw (ClassNotFoundException) pae.getException();
 462         }
 463         if (result == null) {
 464             throw new ClassNotFoundException(name);
 465         }
 466         return result;
 467     }
 468 
 469     /*
 470      * Retrieve the package using the specified package name.
 471      * If non-null, verify the package using the specified code
 472      * source and manifest.
 473      */
 474     private Package getAndVerifyPackage(String pkgname,
 475                                         Manifest man, URL url) {
 476         Package pkg = getDefinedPackage(pkgname);
 477         if (pkg != null) {
 478             // Package found, so check package sealing.
 479             if (pkg.isSealed()) {
 480                 // Verify that code source URL is the same.
 481                 if (!pkg.isSealed(url)) {
 482                     throw new SecurityException(
 483                         "sealing violation: package " + pkgname + " is sealed");
 484                 }
 485             } else {
 486                 // Make sure we are not attempting to seal the package
 487                 // at this code source URL.
 488                 if ((man != null) && isSealed(pkgname, man)) {
 489                     throw new SecurityException(
 490                         "sealing violation: can't seal package " + pkgname +
 491                         ": already loaded");
 492                 }
 493             }
 494         }
 495         return pkg;
 496     }
 497 
 498     /*
 499      * Defines a Class using the class bytes obtained from the specified
 500      * Resource. The resulting Class must be resolved before it can be
 501      * used.
 502      */
 503     private Class<?> defineClass(String name, Resource res) throws IOException {
 504         long t0 = System.nanoTime();
 505         int i = name.lastIndexOf('.');
 506         URL url = res.getCodeSourceURL();
 507         if (i != -1) {
 508             String pkgname = name.substring(0, i);
 509             // Check if package already loaded.
 510             Manifest man = res.getManifest();
 511             if (getAndVerifyPackage(pkgname, man, url) == null) {
 512                 try {
 513                     if (man != null) {
 514                         definePackage(pkgname, man, url);
 515                     } else {
 516                         definePackage(pkgname, null, null, null, null, null, null, null);
 517                     }
 518                 } catch (IllegalArgumentException iae) {
 519                     // parallel-capable class loaders: re-verify in case of a
 520                     // race condition
 521                     if (getAndVerifyPackage(pkgname, man, url) == null) {
 522                         // Should never happen
 523                         throw new AssertionError("Cannot find package " +
 524                                                  pkgname);
 525                     }
 526                 }
 527             }
 528         }
 529         // Now read the class bytes and define the class
 530         java.nio.ByteBuffer bb = res.getByteBuffer();
 531         if (bb != null) {
 532             // Use (direct) ByteBuffer:
 533             CodeSigner[] signers = res.getCodeSigners();
 534             CodeSource cs = new CodeSource(url, signers);
 535             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
 536             return defineClass(name, bb, cs);
 537         } else {
 538             byte[] b = res.getBytes();
 539             // must read certificates AFTER reading bytes.
 540             CodeSigner[] signers = res.getCodeSigners();
 541             CodeSource cs = new CodeSource(url, signers);
 542             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
 543             return defineClass(name, b, 0, b.length, cs);
 544         }
 545     }
 546 
 547     /**
 548      * Defines a new package by name in this {@code URLClassLoader}.
 549      * The attributes contained in the specified {@code Manifest}
 550      * will be used to obtain package version and sealing information.
 551      * For sealed packages, the additional URL specifies the code source URL
 552      * from which the package was loaded.
 553      *
 554      * @param name  the package name
 555      * @param man   the {@code Manifest} containing package version and sealing
 556      *              information
 557      * @param url   the code source url for the package, or null if none
 558      * @throws      IllegalArgumentException if the package name is
 559      *              already defined by this class loader
 560      * @return      the newly defined {@code Package} object
 561      */
 562     protected Package definePackage(String name, Manifest man, URL url) {
 563         String path = name.replace('.', '/').concat("/");
 564         String specTitle = null, specVersion = null, specVendor = null;
 565         String implTitle = null, implVersion = null, implVendor = null;
 566         String sealed = null;
 567         URL sealBase = null;
 568 
 569         Attributes attr = man.getAttributes(path);
 570         if (attr != null) {
 571             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
 572             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
 573             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
 574             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
 575             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
 576             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
 577             sealed      = attr.getValue(Name.SEALED);
 578         }
 579         attr = man.getMainAttributes();
 580         if (attr != null) {
 581             if (specTitle == null) {
 582                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
 583             }
 584             if (specVersion == null) {
 585                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
 586             }
 587             if (specVendor == null) {
 588                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
 589             }
 590             if (implTitle == null) {
 591                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
 592             }
 593             if (implVersion == null) {
 594                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
 595             }
 596             if (implVendor == null) {
 597                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
 598             }
 599             if (sealed == null) {
 600                 sealed = attr.getValue(Name.SEALED);
 601             }
 602         }
 603         if ("true".equalsIgnoreCase(sealed)) {
 604             sealBase = url;
 605         }
 606         return definePackage(name, specTitle, specVersion, specVendor,
 607                              implTitle, implVersion, implVendor, sealBase);
 608     }
 609 
 610     /*
 611      * Returns true if the specified package name is sealed according to the
 612      * given manifest.
 613      */
 614     private boolean isSealed(String name, Manifest man) {
 615         String path = name.replace('.', '/').concat("/");
 616         Attributes attr = man.getAttributes(path);
 617         String sealed = null;
 618         if (attr != null) {
 619             sealed = attr.getValue(Name.SEALED);
 620         }
 621         if (sealed == null) {
 622             if ((attr = man.getMainAttributes()) != null) {
 623                 sealed = attr.getValue(Name.SEALED);
 624             }
 625         }
 626         return "true".equalsIgnoreCase(sealed);
 627     }
 628 
 629     /**
 630      * Finds the resource with the specified name on the URL search path.
 631      *
 632      * @param name the name of the resource
 633      * @return a {@code URL} for the resource, or {@code null}
 634      * if the resource could not be found, or if the loader is closed.
 635      */
 636     public URL findResource(final String name) {
 637         /*
 638          * The same restriction to finding classes applies to resources
 639          */
 640         URL url = AccessController.doPrivileged(
 641             new PrivilegedAction<>() {
 642                 public URL run() {
 643                     return ucp.findResource(name, true);
 644                 }
 645             }, acc);
 646 
 647         return url != null ? URLClassPath.checkURL(url) : null;
 648     }
 649 
 650     /**
 651      * Returns an Enumeration of URLs representing all of the resources
 652      * on the URL search path having the specified name.
 653      *
 654      * @param name the resource name
 655      * @exception IOException if an I/O exception occurs
 656      * @return an {@code Enumeration} of {@code URL}s
 657      *         If the loader is closed, the Enumeration will be empty.
 658      */
 659     public Enumeration<URL> findResources(final String name)
 660         throws IOException
 661     {
 662         final Enumeration<URL> e = ucp.findResources(name, true);
 663 
 664         return new Enumeration<>() {
 665             private URL url = null;
 666 
 667             private boolean next() {
 668                 if (url != null) {
 669                     return true;
 670                 }
 671                 do {
 672                     URL u = AccessController.doPrivileged(
 673                         new PrivilegedAction<>() {
 674                             public URL run() {
 675                                 if (!e.hasMoreElements())
 676                                     return null;
 677                                 return e.nextElement();
 678                             }
 679                         }, acc);
 680                     if (u == null)
 681                         break;
 682                     url = URLClassPath.checkURL(u);
 683                 } while (url == null);
 684                 return url != null;
 685             }
 686 
 687             public URL nextElement() {
 688                 if (!next()) {
 689                     throw new NoSuchElementException();
 690                 }
 691                 URL u = url;
 692                 url = null;
 693                 return u;
 694             }
 695 
 696             public boolean hasMoreElements() {
 697                 return next();
 698             }
 699         };
 700     }
 701 
 702     /**
 703      * Returns the permissions for the given codesource object.
 704      * The implementation of this method first calls super.getPermissions
 705      * and then adds permissions based on the URL of the codesource.
 706      * <p>
 707      * If the protocol of this URL is "jar", then the permission granted
 708      * is based on the permission that is required by the URL of the Jar
 709      * file.
 710      * <p>
 711      * If the protocol is "file" and there is an authority component, then
 712      * permission to connect to and accept connections from that authority
 713      * may be granted. If the protocol is "file"
 714      * and the path specifies a file, then permission to read that
 715      * file is granted. If protocol is "file" and the path is
 716      * a directory, permission is granted to read all files
 717      * and (recursively) all files and subdirectories contained in
 718      * that directory.
 719      * <p>
 720      * If the protocol is not "file", then permission
 721      * to connect to and accept connections from the URL's host is granted.
 722      * @param codesource the codesource
 723      * @exception NullPointerException if {@code codesource} is {@code null}.
 724      * @return the permissions granted to the codesource
 725      */
 726     protected PermissionCollection getPermissions(CodeSource codesource)
 727     {
 728         PermissionCollection perms = super.getPermissions(codesource);
 729 
 730         URL url = codesource.getLocation();
 731 
 732         Permission p;
 733         URLConnection urlConnection;
 734 
 735         try {
 736             urlConnection = url.openConnection();
 737             p = urlConnection.getPermission();
 738         } catch (java.io.IOException ioe) {
 739             p = null;
 740             urlConnection = null;
 741         }
 742 
 743         if (p instanceof FilePermission) {
 744             // if the permission has a separator char on the end,
 745             // it means the codebase is a directory, and we need
 746             // to add an additional permission to read recursively
 747             String path = p.getName();
 748             if (path.endsWith(File.separator)) {
 749                 path += "-";
 750                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 751             }
 752         } else if ((p == null) && (url.getProtocol().equals("file"))) {
 753             String path = url.getFile().replace('/', File.separatorChar);
 754             path = ParseUtil.decode(path);
 755             if (path.endsWith(File.separator))
 756                 path += "-";
 757             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 758         } else {
 759             /**
 760              * Not loading from a 'file:' URL so we want to give the class
 761              * permission to connect to and accept from the remote host
 762              * after we've made sure the host is the correct one and is valid.
 763              */
 764             URL locUrl = url;
 765             if (urlConnection instanceof JarURLConnection) {
 766                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
 767             }
 768             String host = locUrl.getHost();
 769             if (host != null && (host.length() > 0))
 770                 p = new SocketPermission(host,
 771                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
 772         }
 773 
 774         // make sure the person that created this class loader
 775         // would have this permission
 776 
 777         if (p != null) {
 778             final SecurityManager sm = System.getSecurityManager();
 779             if (sm != null) {
 780                 final Permission fp = p;
 781                 AccessController.doPrivileged(new PrivilegedAction<>() {
 782                     public Void run() throws SecurityException {
 783                         sm.checkPermission(fp);
 784                         return null;
 785                     }
 786                 }, acc);
 787             }
 788             perms.add(p);
 789         }
 790         return perms;
 791     }
 792 
 793     /**
 794      * Creates a new instance of URLClassLoader for the specified
 795      * URLs and parent class loader. If a security manager is
 796      * installed, the {@code loadClass} method of the URLClassLoader
 797      * returned by this method will invoke the
 798      * {@code SecurityManager.checkPackageAccess} method before
 799      * loading the class.
 800      *
 801      * @param urls the URLs to search for classes and resources
 802      * @param parent the parent class loader for delegation
 803      * @exception  NullPointerException if {@code urls} is {@code null}.
 804      * @return the resulting class loader
 805      */
 806     public static URLClassLoader newInstance(final URL[] urls,
 807                                              final ClassLoader parent) {
 808         // Save the caller's context
 809         final AccessControlContext acc = AccessController.getContext();
 810         // Need a privileged block to create the class loader
 811         URLClassLoader ucl = AccessController.doPrivileged(
 812             new PrivilegedAction<>() {
 813                 public URLClassLoader run() {
 814                     return new FactoryURLClassLoader(null, urls, parent, acc);
 815                 }
 816             });
 817         return ucl;
 818     }
 819 
 820     /**
 821      * Creates a new instance of URLClassLoader for the specified
 822      * URLs and default parent class loader. If a security manager is
 823      * installed, the {@code loadClass} method of the URLClassLoader
 824      * returned by this method will invoke the
 825      * {@code SecurityManager.checkPackageAccess} before
 826      * loading the class.
 827      *
 828      * @param urls the URLs to search for classes and resources
 829      * @exception  NullPointerException if {@code urls} is {@code null}.
 830      * @return the resulting class loader
 831      */
 832     public static URLClassLoader newInstance(final URL[] urls) {
 833         // Save the caller's context
 834         final AccessControlContext acc = AccessController.getContext();
 835         // Need a privileged block to create the class loader
 836         URLClassLoader ucl = AccessController.doPrivileged(
 837             new PrivilegedAction<>() {
 838                 public URLClassLoader run() {
 839                     return new FactoryURLClassLoader(urls, acc);
 840                 }
 841             });
 842         return ucl;
 843     }
 844 
 845     static {
 846         SharedSecrets.setJavaNetURLClassLoaderAccess(
 847             new JavaNetURLClassLoaderAccess() {
 848                 @Override
 849                 public AccessControlContext getAccessControlContext(URLClassLoader u) {
 850                     return u.acc;
 851                 }
 852             }
 853         );
 854         ClassLoader.registerAsParallelCapable();
 855     }
 856 }
 857 
 858 final class FactoryURLClassLoader extends URLClassLoader {
 859 
 860     static {
 861         ClassLoader.registerAsParallelCapable();
 862     }
 863 
 864     FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent,
 865                           AccessControlContext acc) {
 866         super(name, urls, parent, acc);
 867     }
 868 
 869     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
 870         super(urls, acc);
 871     }
 872 
 873     public final Class<?> loadClass(String name, boolean resolve)
 874         throws ClassNotFoundException
 875     {
 876         // First check if we have permission to access the package. This
 877         // should go away once we've added support for exported packages.
 878         SecurityManager sm = System.getSecurityManager();
 879         if (sm != null) {
 880             int i = name.lastIndexOf('.');
 881             if (i != -1) {
 882                 sm.checkPackageAccess(name.substring(0, i));
 883             }
 884         }
 885         return super.loadClass(name, resolve);
 886     }
 887 }