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.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 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 specTitle = null, specVersion = null, specVendor = null;
 574         String implTitle = null, implVersion = null, implVendor = null;
 575         String sealed = null;
 576         URL sealBase = null;
 577 
 578         Attributes attr = SharedSecrets.javaUtilJarAccess()
 579                 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
 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      * @throws SecurityException if the package name is untrusted in the manifest
 625      */
 626     private boolean isSealed(String name, Manifest man) {
 627         Attributes attr = SharedSecrets.javaUtilJarAccess()
 628                 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
 629         String sealed = null;
 630         if (attr != null) {
 631             sealed = attr.getValue(Name.SEALED);
 632         }
 633         if (sealed == null) {
 634             if ((attr = man.getMainAttributes()) != null) {
 635                 sealed = attr.getValue(Name.SEALED);
 636             }
 637         }
 638         return "true".equalsIgnoreCase(sealed);
 639     }
 640 
 641     /**
 642      * Finds the resource with the specified name on the URL search path.
 643      *
 644      * @param name the name of the resource
 645      * @return a {@code URL} for the resource, or {@code null}
 646      * if the resource could not be found, or if the loader is closed.
 647      */
 648     public URL findResource(final String name) {
 649         /*
 650          * The same restriction to finding classes applies to resources
 651          */
 652         URL url = AccessController.doPrivileged(
 653             new PrivilegedAction<>() {
 654                 public URL run() {
 655                     return ucp.findResource(name, true);
 656                 }
 657             }, acc);
 658 
 659         return url != null ? URLClassPath.checkURL(url) : null;
 660     }
 661 
 662     /**
 663      * Returns an Enumeration of URLs representing all of the resources
 664      * on the URL search path having the specified name.
 665      *
 666      * @param name the resource name
 667      * @exception IOException if an I/O exception occurs
 668      * @return An {@code Enumeration} of {@code URL}s.
 669      *         If the loader is closed, the Enumeration contains no elements.
 670      */
 671     public Enumeration<URL> findResources(final String name)
 672         throws IOException
 673     {
 674         final Enumeration<URL> e = ucp.findResources(name, true);
 675 
 676         return new Enumeration<>() {
 677             private URL url = null;
 678 
 679             private boolean next() {
 680                 if (url != null) {
 681                     return true;
 682                 }
 683                 do {
 684                     URL u = AccessController.doPrivileged(
 685                         new PrivilegedAction<>() {
 686                             public URL run() {
 687                                 if (!e.hasMoreElements())
 688                                     return null;
 689                                 return e.nextElement();
 690                             }
 691                         }, acc);
 692                     if (u == null)
 693                         break;
 694                     url = URLClassPath.checkURL(u);
 695                 } while (url == null);
 696                 return url != null;
 697             }
 698 
 699             public URL nextElement() {
 700                 if (!next()) {
 701                     throw new NoSuchElementException();
 702                 }
 703                 URL u = url;
 704                 url = null;
 705                 return u;
 706             }
 707 
 708             public boolean hasMoreElements() {
 709                 return next();
 710             }
 711         };
 712     }
 713 
 714     /**
 715      * Returns the permissions for the given codesource object.
 716      * The implementation of this method first calls super.getPermissions
 717      * and then adds permissions based on the URL of the codesource.
 718      * <p>
 719      * If the protocol of this URL is "jar", then the permission granted
 720      * is based on the permission that is required by the URL of the Jar
 721      * file.
 722      * <p>
 723      * If the protocol is "file" and there is an authority component, then
 724      * permission to connect to and accept connections from that authority
 725      * may be granted. If the protocol is "file"
 726      * and the path specifies a file, then permission to read that
 727      * file is granted. If protocol is "file" and the path is
 728      * a directory, permission is granted to read all files
 729      * and (recursively) all files and subdirectories contained in
 730      * that directory.
 731      * <p>
 732      * If the protocol is not "file", then permission
 733      * to connect to and accept connections from the URL's host is granted.
 734      * @param codesource the codesource
 735      * @exception NullPointerException if {@code codesource} is {@code null}.
 736      * @return the permissions granted to the codesource
 737      */
 738     protected PermissionCollection getPermissions(CodeSource codesource)
 739     {
 740         PermissionCollection perms = super.getPermissions(codesource);
 741 
 742         URL url = codesource.getLocation();
 743 
 744         Permission p;
 745         URLConnection urlConnection;
 746 
 747         try {
 748             urlConnection = url.openConnection();
 749             p = urlConnection.getPermission();
 750         } catch (java.io.IOException ioe) {
 751             p = null;
 752             urlConnection = null;
 753         }
 754 
 755         if (p instanceof FilePermission) {
 756             // if the permission has a separator char on the end,
 757             // it means the codebase is a directory, and we need
 758             // to add an additional permission to read recursively
 759             String path = p.getName();
 760             if (path.endsWith(File.separator)) {
 761                 path += "-";
 762                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 763             }
 764         } else if ((p == null) && (url.getProtocol().equals("file"))) {
 765             String path = url.getFile().replace('/', File.separatorChar);
 766             path = ParseUtil.decode(path);
 767             if (path.endsWith(File.separator))
 768                 path += "-";
 769             p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 770         } else {
 771             /**
 772              * Not loading from a 'file:' URL so we want to give the class
 773              * permission to connect to and accept from the remote host
 774              * after we've made sure the host is the correct one and is valid.
 775              */
 776             URL locUrl = url;
 777             if (urlConnection instanceof JarURLConnection) {
 778                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
 779             }
 780             String host = locUrl.getHost();
 781             if (host != null && !host.isEmpty())
 782                 p = new SocketPermission(host,
 783                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
 784         }
 785 
 786         // make sure the person that created this class loader
 787         // would have this permission
 788 
 789         if (p != null) {
 790             final SecurityManager sm = System.getSecurityManager();
 791             if (sm != null) {
 792                 final Permission fp = p;
 793                 AccessController.doPrivileged(new PrivilegedAction<>() {
 794                     public Void run() throws SecurityException {
 795                         sm.checkPermission(fp);
 796                         return null;
 797                     }
 798                 }, acc);
 799             }
 800             perms.add(p);
 801         }
 802         return perms;
 803     }
 804 
 805     /**
 806      * Creates a new instance of URLClassLoader for the specified
 807      * URLs and parent class loader. If a security manager is
 808      * installed, the {@code loadClass} method of the URLClassLoader
 809      * returned by this method will invoke the
 810      * {@code SecurityManager.checkPackageAccess} method before
 811      * loading the class.
 812      *
 813      * @param urls the URLs to search for classes and resources
 814      * @param parent the parent class loader for delegation
 815      * @exception  NullPointerException if {@code urls} or any of its
 816      *             elements is {@code null}.
 817      * @return the resulting class loader
 818      */
 819     public static URLClassLoader newInstance(final URL[] urls,
 820                                              final ClassLoader parent) {
 821         // Save the caller's context
 822         final AccessControlContext acc = AccessController.getContext();
 823         // Need a privileged block to create the class loader
 824         URLClassLoader ucl = AccessController.doPrivileged(
 825             new PrivilegedAction<>() {
 826                 public URLClassLoader run() {
 827                     return new FactoryURLClassLoader(null, urls, parent, acc);
 828                 }
 829             });
 830         return ucl;
 831     }
 832 
 833     /**
 834      * Creates a new instance of URLClassLoader for the specified
 835      * URLs and default parent class loader. If a security manager is
 836      * installed, the {@code loadClass} method of the URLClassLoader
 837      * returned by this method will invoke the
 838      * {@code SecurityManager.checkPackageAccess} before
 839      * loading the class.
 840      *
 841      * @param urls the URLs to search for classes and resources
 842      * @exception  NullPointerException if {@code urls} or any of its
 843      *             elements is {@code null}.
 844      * @return the resulting class loader
 845      */
 846     public static URLClassLoader newInstance(final URL[] urls) {
 847         // Save the caller's context
 848         final AccessControlContext acc = AccessController.getContext();
 849         // Need a privileged block to create the class loader
 850         URLClassLoader ucl = AccessController.doPrivileged(
 851             new PrivilegedAction<>() {
 852                 public URLClassLoader run() {
 853                     return new FactoryURLClassLoader(urls, acc);
 854                 }
 855             });
 856         return ucl;
 857     }
 858 
 859     static {
 860         SharedSecrets.setJavaNetURLClassLoaderAccess(
 861             new JavaNetURLClassLoaderAccess() {
 862                 @Override
 863                 public AccessControlContext getAccessControlContext(URLClassLoader u) {
 864                     return u.acc;
 865                 }
 866             }
 867         );
 868         ClassLoader.registerAsParallelCapable();
 869     }
 870 }
 871 
 872 final class FactoryURLClassLoader extends URLClassLoader {
 873 
 874     static {
 875         ClassLoader.registerAsParallelCapable();
 876     }
 877 
 878     FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent,
 879                           AccessControlContext acc) {
 880         super(name, urls, parent, acc);
 881     }
 882 
 883     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
 884         super(urls, acc);
 885     }
 886 
 887     public final Class<?> loadClass(String name, boolean resolve)
 888         throws ClassNotFoundException
 889     {
 890         // First check if we have permission to access the package. This
 891         // should go away once we've added support for exported packages.
 892         SecurityManager sm = System.getSecurityManager();
 893         if (sm != null) {
 894             int i = name.lastIndexOf('.');
 895             if (i != -1) {
 896                 sm.checkPackageAccess(name.substring(0, i));
 897             }
 898         }
 899         return super.loadClass(name, resolve);
 900     }
 901 }