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