Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package java.net;
     27 
     28 import java.io.Closeable;
     29 import java.io.File;
     30 import java.io.FilePermission;
     31 import java.io.IOException;
     32 import java.io.InputStream;
     33 import java.security.AccessControlContext;
     34 import java.security.AccessController;
     35 import java.security.CodeSigner;
     36 import java.security.CodeSource;
     37 import java.security.Permission;
     38 import java.security.PermissionCollection;
     39 import java.security.PrivilegedAction;
     40 import java.security.PrivilegedExceptionAction;
     41 import java.security.SecureClassLoader;
     42 import java.util.Enumeration;
     43 import java.util.List;
     44 import java.util.NoSuchElementException;
     45 import java.util.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         this.acc = AccessController.getContext();
    107         ucp = new URLClassPath(urls, acc);
    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         this.acc = acc;
    119         ucp = new URLClassPath(urls, 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         this.acc = AccessController.getContext();
    151         ucp = new URLClassPath(urls, acc);
    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         this.acc = acc;
    162         ucp = new URLClassPath(urls, 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         acc = AccessController.getContext();
    195         ucp = new URLClassPath(urls, factory, acc);
    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     * <p>
    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         final Class<?> result;
    360         try {
    361             result = AccessController.doPrivileged(
    362                 new PrivilegedExceptionAction<Class<?>>() {
    363                     public Class<?> run() throws ClassNotFoundException {
    364                         String path = name.replace('.', '/').concat(".class");
    365                         Resource res = ucp.getResource(path, false);
    366                         if (res != null) {
    367                             try {
    368                                 return defineClass(name, res);
    369                             } catch (IOException e) {
    370                                 throw new ClassNotFoundException(name, e);
    371                             }
    372                         } else {
    373                             return null;
    374                         }
    375                     }
    376                 }, acc);
    377         } catch (java.security.PrivilegedActionException pae) {
    378             throw (ClassNotFoundException) pae.getException();
    379         }
    380         if (result == null) {
    381             throw new ClassNotFoundException(name);
    382         }
    383         return result;
    384     }
    385 
    386     /*
    387      * Retrieve the package using the specified package name.
    388      * If non-null, verify the package using the specified code
    389      * source and manifest.
    390      */
    391     private Package getAndVerifyPackage(String pkgname,
    392                                         Manifest man, URL url) {
    393         Package pkg = getPackage(pkgname);
    394         if (pkg != null) {
    395             // Package found, so check package sealing.
    396             if (pkg.isSealed()) {
    397                 // Verify that code source URL is the same.
    398                 if (!pkg.isSealed(url)) {
    399                     throw new SecurityException(
    400                         "sealing violation: package " + pkgname + " is sealed");
    401                 }
    402             } else {
    403                 // Make sure we are not attempting to seal the package
    404                 // at this code source URL.
    405                 if ((man != null) && isSealed(pkgname, man)) {
    406                     throw new SecurityException(
    407                         "sealing violation: can't seal package " + pkgname +
    408                         ": already loaded");
    409                 }
    410             }
    411         }
    412         return pkg;
    413     }
    414 
    415     // Also called by VM to define Package for classes loaded from the CDS
    416     // archive
    417     private void definePackageInternal(String pkgname, Manifest man, URL url)
    418     {
    419         if (getAndVerifyPackage(pkgname, man, url) == null) {
    420             try {
    421                 if (man != null) {
    422                     definePackage(pkgname, man, url);
    423                 } else {
    424                     definePackage(pkgname, null, null, null, null, null, null, null);
    425                 }
    426             } catch (IllegalArgumentException iae) {
    427                 // parallel-capable class loaders: re-verify in case of a
    428                 // race condition
    429                 if (getAndVerifyPackage(pkgname, man, url) == null) {
    430                     // Should never happen
    431                     throw new AssertionError("Cannot find package " +
    432                                              pkgname);
    433                 }
    434             }
    435         }
    436     }
    437 
    438     /*
    439      * Defines a Class using the class bytes obtained from the specified
    440      * Resource. The resulting Class must be resolved before it can be
    441      * used.
    442      */
    443     private Class<?> defineClass(String name, Resource res) throws IOException {
    444         long t0 = System.nanoTime();
    445         int i = name.lastIndexOf('.');
    446         URL url = res.getCodeSourceURL();
    447         if (i != -1) {
    448             String pkgname = name.substring(0, i);
    449             // Check if package already loaded.
    450             Manifest man = res.getManifest();
    451             definePackageInternal(pkgname, man, url);
    452         }
    453         // Now read the class bytes and define the class
    454         java.nio.ByteBuffer bb = res.getByteBuffer();
    455         if (bb != null) {
    456             // Use (direct) ByteBuffer:
    457             CodeSigner[] signers = res.getCodeSigners();
    458             CodeSource cs = new CodeSource(url, signers);
    459             // Android-removed: Android doesn't use sun.misc.PerfCounter.
    460             // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
    461             return defineClass(name, bb, cs);
    462         } else {
    463             byte[] b = res.getBytes();
    464             // must read certificates AFTER reading bytes.
    465             CodeSigner[] signers = res.getCodeSigners();
    466             CodeSource cs = new CodeSource(url, signers);
    467             // Android-removed: Android doesn't use sun.misc.PerfCounter.
    468             // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
    469             return defineClass(name, b, 0, b.length, cs);
    470         }
    471     }
    472 
    473     /**
    474      * Defines a new package by name in this ClassLoader. The attributes
    475      * contained in the specified Manifest will be used to obtain package
    476      * version and sealing information. For sealed packages, the additional
    477      * URL specifies the code source URL from which the package was loaded.
    478      *
    479      * @param name  the package name
    480      * @param man   the Manifest containing package version and sealing
    481      *              information
    482      * @param url   the code source url for the package, or null if none
    483      * @exception   IllegalArgumentException if the package name duplicates
    484      *              an existing package either in this class loader or one
    485      *              of its ancestors
    486      * @return the newly defined Package object
    487      */
    488     protected Package definePackage(String name, Manifest man, URL url)
    489         throws IllegalArgumentException
    490     {
    491         String path = name.replace('.', '/').concat("/");
    492         String specTitle = null, specVersion = null, specVendor = null;
    493         String implTitle = null, implVersion = null, implVendor = null;
    494         String sealed = null;
    495         URL sealBase = null;
    496 
    497         Attributes attr = man.getAttributes(path);
    498         if (attr != null) {
    499             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
    500             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
    501             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
    502             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
    503             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
    504             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
    505             sealed      = attr.getValue(Name.SEALED);
    506         }
    507         attr = man.getMainAttributes();
    508         if (attr != null) {
    509             if (specTitle == null) {
    510                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
    511             }
    512             if (specVersion == null) {
    513                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
    514             }
    515             if (specVendor == null) {
    516                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
    517             }
    518             if (implTitle == null) {
    519                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
    520             }
    521             if (implVersion == null) {
    522                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
    523             }
    524             if (implVendor == null) {
    525                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
    526             }
    527             if (sealed == null) {
    528                 sealed = attr.getValue(Name.SEALED);
    529             }
    530         }
    531         if ("true".equalsIgnoreCase(sealed)) {
    532             sealBase = url;
    533         }
    534         return definePackage(name, specTitle, specVersion, specVendor,
    535                              implTitle, implVersion, implVendor, sealBase);
    536     }
    537 
    538     /*
    539      * Returns true if the specified package name is sealed according to the
    540      * given manifest.
    541      */
    542     private boolean isSealed(String name, Manifest man) {
    543         String path = name.replace('.', '/').concat("/");
    544         Attributes attr = man.getAttributes(path);
    545         String sealed = null;
    546         if (attr != null) {
    547             sealed = attr.getValue(Name.SEALED);
    548         }
    549         if (sealed == null) {
    550             if ((attr = man.getMainAttributes()) != null) {
    551                 sealed = attr.getValue(Name.SEALED);
    552             }
    553         }
    554         return "true".equalsIgnoreCase(sealed);
    555     }
    556 
    557     /**
    558      * Finds the resource with the specified name on the URL search path.
    559      *
    560      * @param name the name of the resource
    561      * @return a {@code URL} for the resource, or {@code null}
    562      * if the resource could not be found, or if the loader is closed.
    563      */
    564     public URL findResource(final String name) {
    565         /*
    566          * The same restriction to finding classes applies to resources
    567          */
    568         URL url = AccessController.doPrivileged(
    569             new PrivilegedAction<URL>() {
    570                 public URL run() {
    571                     return ucp.findResource(name, true);
    572                 }
    573             }, acc);
    574 
    575         return url != null ? ucp.checkURL(url) : null;
    576     }
    577 
    578     /**
    579      * Returns an Enumeration of URLs representing all of the resources
    580      * on the URL search path having the specified name.
    581      *
    582      * @param name the resource name
    583      * @exception IOException if an I/O exception occurs
    584      * @return an {@code Enumeration} of {@code URL}s
    585      *         If the loader is closed, the Enumeration will be empty.
    586      */
    587     public Enumeration<URL> findResources(final String name)
    588         throws IOException
    589     {
    590         final Enumeration<URL> e = ucp.findResources(name, true);
    591 
    592         return new Enumeration<URL>() {
    593             private URL url = null;
    594 
    595             private boolean next() {
    596                 if (url != null) {
    597                     return true;
    598                 }
    599                 do {
    600                     URL u = AccessController.doPrivileged(
    601                         new PrivilegedAction<URL>() {
    602                             public URL run() {
    603                                 if (!e.hasMoreElements())
    604                                     return null;
    605                                 return e.nextElement();
    606                             }
    607                         }, acc);
    608                     if (u == null)
    609                         break;
    610                     url = ucp.checkURL(u);
    611                 } while (url == null);
    612                 return url != null;
    613             }
    614 
    615             public URL nextElement() {
    616                 if (!next()) {
    617                     throw new NoSuchElementException();
    618                 }
    619                 URL u = url;
    620                 url = null;
    621                 return u;
    622             }
    623 
    624             public boolean hasMoreElements() {
    625                 return next();
    626             }
    627         };
    628     }
    629 
    630     /**
    631      * Returns the permissions for the given codesource object.
    632      * The implementation of this method first calls super.getPermissions
    633      * and then adds permissions based on the URL of the codesource.
    634      * <p>
    635      * If the protocol of this URL is "jar", then the permission granted
    636      * is based on the permission that is required by the URL of the Jar
    637      * file.
    638      * <p>
    639      * If the protocol is "file" and there is an authority component, then
    640      * permission to connect to and accept connections from that authority
    641      * may be granted. If the protocol is "file"
    642      * and the path specifies a file, then permission to read that
    643      * file is granted. If protocol is "file" and the path is
    644      * a directory, permission is granted to read all files
    645      * and (recursively) all files and subdirectories contained in
    646      * that directory.
    647      * <p>
    648      * If the protocol is not "file", then permission
    649      * to connect to and accept connections from the URL's host is granted.
    650      * @param codesource the codesource
    651      * @exception NullPointerException if {@code codesource} is {@code null}.
    652      * @return the permissions granted to the codesource
    653      */
    654     protected PermissionCollection getPermissions(CodeSource codesource)
    655     {
    656         PermissionCollection perms = super.getPermissions(codesource);
    657 
    658         URL url = codesource.getLocation();
    659 
    660         Permission p;
    661         URLConnection urlConnection;
    662 
    663         try {
    664             urlConnection = url.openConnection();
    665             p = urlConnection.getPermission();
    666         } catch (java.io.IOException ioe) {
    667             p = null;
    668             urlConnection = null;
    669         }
    670 
    671         if (p instanceof FilePermission) {
    672             // if the permission has a separator char on the end,
    673             // it means the codebase is a directory, and we need
    674             // to add an additional permission to read recursively
    675             String path = p.getName();
    676             if (path.endsWith(File.separator)) {
    677                 path += "-";
    678                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
    679             }
    680         } else if ((p == null) && (url.getProtocol().equals("file"))) {
    681             String path = url.getFile().replace('/', File.separatorChar);
    682             path = ParseUtil.decode(path);
    683             if (path.endsWith(File.separator))
    684                 path += "-";
    685             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
    686         } else {
    687             /**
    688              * Not loading from a 'file:' URL so we want to give the class
    689              * permission to connect to and accept from the remote host
    690              * after we've made sure the host is the correct one and is valid.
    691              */
    692             URL locUrl = url;
    693             if (urlConnection instanceof JarURLConnection) {
    694                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
    695             }
    696             String host = locUrl.getHost();
    697             if (host != null && (host.length() > 0))
    698                 p = new SocketPermission(host,
    699                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
    700         }
    701 
    702         // make sure the person that created this class loader
    703         // would have this permission
    704 
    705         if (p != null) {
    706             final SecurityManager sm = System.getSecurityManager();
    707             if (sm != null) {
    708                 final Permission fp = p;
    709                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
    710                     public Void run() throws SecurityException {
    711                         sm.checkPermission(fp);
    712                         return null;
    713                     }
    714                 }, acc);
    715             }
    716             perms.add(p);
    717         }
    718         return perms;
    719     }
    720 
    721     /**
    722      * Creates a new instance of URLClassLoader for the specified
    723      * URLs and parent class loader. If a security manager is
    724      * installed, the {@code loadClass} method of the URLClassLoader
    725      * returned by this method will invoke the
    726      * {@code SecurityManager.checkPackageAccess} method before
    727      * loading the class.
    728      *
    729      * @param urls the URLs to search for classes and resources
    730      * @param parent the parent class loader for delegation
    731      * @exception  NullPointerException if {@code urls} is {@code null}.
    732      * @return the resulting class loader
    733      */
    734     public static URLClassLoader newInstance(final URL[] urls,
    735                                              final ClassLoader parent) {
    736         // Save the caller's context
    737         final AccessControlContext acc = AccessController.getContext();
    738         // Need a privileged block to create the class loader
    739         URLClassLoader ucl = AccessController.doPrivileged(
    740             new PrivilegedAction<URLClassLoader>() {
    741                 public URLClassLoader run() {
    742                     return new FactoryURLClassLoader(urls, parent, acc);
    743                 }
    744             });
    745         return ucl;
    746     }
    747 
    748     /**
    749      * Creates a new instance of URLClassLoader for the specified
    750      * URLs and default parent class loader. If a security manager is
    751      * installed, the {@code loadClass} method of the URLClassLoader
    752      * returned by this method will invoke the
    753      * {@code SecurityManager.checkPackageAccess} before
    754      * loading the class.
    755      *
    756      * @param urls the URLs to search for classes and resources
    757      * @exception  NullPointerException if {@code urls} is {@code null}.
    758      * @return the resulting class loader
    759      */
    760     public static URLClassLoader newInstance(final URL[] urls) {
    761         // Save the caller's context
    762         final AccessControlContext acc = AccessController.getContext();
    763         // Need a privileged block to create the class loader
    764         URLClassLoader ucl = AccessController.doPrivileged(
    765             new PrivilegedAction<URLClassLoader>() {
    766                 public URLClassLoader run() {
    767                     return new FactoryURLClassLoader(urls, acc);
    768                 }
    769             });
    770         return ucl;
    771     }
    772 
    773     static {
    774         // Android-removed: SharedSecrets.setJavaNetAccess call. Android doesn't use it.
    775         /*sun.misc.SharedSecrets.setJavaNetAccess (
    776             new sun.misc.JavaNetAccess() {
    777                 public URLClassPath getURLClassPath (URLClassLoader u) {
    778                     return u.ucp;
    779                 }
    780 
    781                 public String getOriginalHostName(InetAddress ia) {
    782                     return ia.holder.getOriginalHostName();
    783                 }
    784             }
    785         );*/
    786         ClassLoader.registerAsParallelCapable();
    787     }
    788 }
    789 
    790 final class FactoryURLClassLoader extends URLClassLoader {
    791 
    792     static {
    793         ClassLoader.registerAsParallelCapable();
    794     }
    795 
    796     FactoryURLClassLoader(URL[] urls, ClassLoader parent,
    797                           AccessControlContext acc) {
    798         super(urls, parent, acc);
    799     }
    800 
    801     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
    802         super(urls, acc);
    803     }
    804 
    805     public final Class<?> loadClass(String name, boolean resolve)
    806         throws ClassNotFoundException
    807     {
    808         // First check if we have permission to access the package. This
    809         // should go away once we've added support for exported packages.
    810         SecurityManager sm = System.getSecurityManager();
    811         if (sm != null) {
    812             int i = name.lastIndexOf('.');
    813             if (i != -1) {
    814                 sm.checkPackageAccess(name.substring(0, i));
    815             }
    816         }
    817         return super.loadClass(name, resolve);
    818     }
    819 }
    820