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