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