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