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