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