1 /*
   2  * Copyright (c) 1997, 2011, 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.*;
  29 import java.util.*;
  30 import java.util.jar.Manifest;
  31 import java.util.jar.JarFile;
  32 import java.util.jar.Attributes;
  33 import java.util.jar.Attributes.Name;
  34 import java.security.CodeSigner;
  35 import java.security.PrivilegedAction;
  36 import java.security.PrivilegedExceptionAction;
  37 import java.security.AccessController;
  38 import java.security.AccessControlContext;
  39 import java.security.SecureClassLoader;
  40 import java.security.CodeSource;
  41 import java.security.Permission;
  42 import java.security.PermissionCollection;
  43 import sun.misc.Resource;
  44 import sun.misc.URLClassPath;
  45 import sun.net.www.ParseUtil;
  46 import sun.security.util.SecurityConstants;
  47 
  48 /**
  49  * This class loader is used to load classes and resources from a search
  50  * path of URLs referring to both JAR files and directories. Any URL that
  51  * ends with a '/' is assumed to refer to a directory. Otherwise, the URL
  52  * is assumed to refer to a JAR file which will be opened as needed.
  53  * <p>
  54  * The AccessControlContext of the thread that created the instance of
  55  * URLClassLoader will be used when subsequently loading classes and
  56  * resources.
  57  * <p>
  58  * The classes that are loaded are by default granted permission only to
  59  * access the URLs specified when the URLClassLoader was created.






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