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