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