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