jdk/src/share/classes/java/net/URLClassLoader.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package java.net;
       
    27 
       
    28 import java.lang.reflect.Method;
       
    29 import java.lang.reflect.Modifier;
       
    30 import java.io.File;
       
    31 import java.io.FilePermission;
       
    32 import java.io.InputStream;
       
    33 import java.io.IOException;
       
    34 import java.net.URL;
       
    35 import java.net.URLConnection;
       
    36 import java.net.URLStreamHandlerFactory;
       
    37 import java.util.Enumeration;
       
    38 import java.util.NoSuchElementException;
       
    39 import java.util.StringTokenizer;
       
    40 import java.util.jar.Manifest;
       
    41 import java.util.jar.Attributes;
       
    42 import java.util.jar.Attributes.Name;
       
    43 import java.security.CodeSigner;
       
    44 import java.security.PrivilegedAction;
       
    45 import java.security.PrivilegedExceptionAction;
       
    46 import java.security.AccessController;
       
    47 import java.security.AccessControlContext;
       
    48 import java.security.SecureClassLoader;
       
    49 import java.security.CodeSource;
       
    50 import java.security.Permission;
       
    51 import java.security.PermissionCollection;
       
    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 {
       
    74     /* The search path for classes and resources */
       
    75     URLClassPath ucp;
       
    76 
       
    77     /* The context to be used when loading classes and resources */
       
    78     private 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</code> 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</code> method doesn't allow
       
    95      *             creation of a class loader.
       
    96      * @see SecurityManager#checkCreateClassLoader
       
    97      */
       
    98     public URLClassLoader(URL[] urls, ClassLoader parent) {
       
    99         super(parent);
       
   100         // this is to make the stack depth consistent with 1.1
       
   101         SecurityManager security = System.getSecurityManager();
       
   102         if (security != null) {
       
   103             security.checkCreateClassLoader();
       
   104         }
       
   105         ucp = new URLClassPath(urls);
       
   106         acc = AccessController.getContext();
       
   107     }
       
   108 
       
   109     /**
       
   110      * Constructs a new URLClassLoader for the specified URLs using the
       
   111      * default delegation parent <code>ClassLoader</code>. The URLs will
       
   112      * be searched in the order specified for classes and resources after
       
   113      * first searching in the parent class loader. Any URL that ends with
       
   114      * a '/' is assumed to refer to a directory. Otherwise, the URL is
       
   115      * assumed to refer to a JAR file which will be downloaded and opened
       
   116      * as needed.
       
   117      *
       
   118      * <p>If there is a security manager, this method first
       
   119      * calls the security manager's <code>checkCreateClassLoader</code> method
       
   120      * to ensure creation of a class loader is allowed.
       
   121      *
       
   122      * @param urls the URLs from which to load classes and resources
       
   123      *
       
   124      * @exception  SecurityException  if a security manager exists and its
       
   125      *             <code>checkCreateClassLoader</code> method doesn't allow
       
   126      *             creation of a class loader.
       
   127      * @see SecurityManager#checkCreateClassLoader
       
   128      */
       
   129     public URLClassLoader(URL[] urls) {
       
   130         super();
       
   131         // this is to make the stack depth consistent with 1.1
       
   132         SecurityManager security = System.getSecurityManager();
       
   133         if (security != null) {
       
   134             security.checkCreateClassLoader();
       
   135         }
       
   136         ucp = new URLClassPath(urls);
       
   137         acc = AccessController.getContext();
       
   138     }
       
   139 
       
   140     /**
       
   141      * Constructs a new URLClassLoader for the specified URLs, parent
       
   142      * class loader, and URLStreamHandlerFactory. The parent argument
       
   143      * will be used as the parent class loader for delegation. The
       
   144      * factory argument will be used as the stream handler factory to
       
   145      * obtain protocol handlers when creating new jar URLs.
       
   146      *
       
   147      * <p>If there is a security manager, this method first
       
   148      * calls the security manager's <code>checkCreateClassLoader</code> method
       
   149      * to ensure creation of a class loader is allowed.
       
   150      *
       
   151      * @param urls the URLs from which to load classes and resources
       
   152      * @param parent the parent class loader for delegation
       
   153      * @param factory the URLStreamHandlerFactory to use when creating URLs
       
   154      *
       
   155      * @exception  SecurityException  if a security manager exists and its
       
   156      *             <code>checkCreateClassLoader</code> method doesn't allow
       
   157      *             creation of a class loader.
       
   158      * @see SecurityManager#checkCreateClassLoader
       
   159      */
       
   160     public URLClassLoader(URL[] urls, ClassLoader parent,
       
   161                           URLStreamHandlerFactory factory) {
       
   162         super(parent);
       
   163         // this is to make the stack depth consistent with 1.1
       
   164         SecurityManager security = System.getSecurityManager();
       
   165         if (security != null) {
       
   166             security.checkCreateClassLoader();
       
   167         }
       
   168         ucp = new URLClassPath(urls, factory);
       
   169         acc = AccessController.getContext();
       
   170     }
       
   171 
       
   172     /**
       
   173      * Appends the specified URL to the list of URLs to search for
       
   174      * classes and resources.
       
   175      * <p>
       
   176      * If the URL specified is <code>null</code> or is already in the
       
   177      * list of URLs, then invoking this method has no effect.
       
   178      *
       
   179      * @param url the URL to be added to the search path of URLs
       
   180      */
       
   181     protected void addURL(URL url) {
       
   182         ucp.addURL(url);
       
   183     }
       
   184 
       
   185     /**
       
   186      * Returns the search path of URLs for loading classes and resources.
       
   187      * This includes the original list of URLs specified to the constructor,
       
   188      * along with any URLs subsequently appended by the addURL() method.
       
   189      * @return the search path of URLs for loading classes and resources.
       
   190      */
       
   191     public URL[] getURLs() {
       
   192         return ucp.getURLs();
       
   193     }
       
   194 
       
   195     /**
       
   196      * Finds and loads the class with the specified name from the URL search
       
   197      * path. Any URLs referring to JAR files are loaded and opened as needed
       
   198      * until the class is found.
       
   199      *
       
   200      * @param name the name of the class
       
   201      * @return the resulting class
       
   202      * @exception ClassNotFoundException if the class could not be found
       
   203      */
       
   204     protected Class<?> findClass(final String name)
       
   205          throws ClassNotFoundException
       
   206     {
       
   207         try {
       
   208             return (Class)
       
   209                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
       
   210                     public Object run() throws ClassNotFoundException {
       
   211                         String path = name.replace('.', '/').concat(".class");
       
   212                         Resource res = ucp.getResource(path, false);
       
   213                         if (res != null) {
       
   214                             try {
       
   215                                 return defineClass(name, res);
       
   216                             } catch (IOException e) {
       
   217                                 throw new ClassNotFoundException(name, e);
       
   218                             }
       
   219                         } else {
       
   220                             throw new ClassNotFoundException(name);
       
   221                         }
       
   222                     }
       
   223                 }, acc);
       
   224         } catch (java.security.PrivilegedActionException pae) {
       
   225             throw (ClassNotFoundException) pae.getException();
       
   226         }
       
   227     }
       
   228 
       
   229     /*
       
   230      * Defines a Class using the class bytes obtained from the specified
       
   231      * Resource. The resulting Class must be resolved before it can be
       
   232      * used.
       
   233      */
       
   234     private Class defineClass(String name, Resource res) throws IOException {
       
   235         int i = name.lastIndexOf('.');
       
   236         URL url = res.getCodeSourceURL();
       
   237         if (i != -1) {
       
   238             String pkgname = name.substring(0, i);
       
   239             // Check if package already loaded.
       
   240             Package pkg = getPackage(pkgname);
       
   241             Manifest man = res.getManifest();
       
   242             if (pkg != null) {
       
   243                 // Package found, so check package sealing.
       
   244                 if (pkg.isSealed()) {
       
   245                     // Verify that code source URL is the same.
       
   246                     if (!pkg.isSealed(url)) {
       
   247                         throw new SecurityException(
       
   248                             "sealing violation: package " + pkgname + " is sealed");
       
   249                     }
       
   250 
       
   251                 } else {
       
   252                     // Make sure we are not attempting to seal the package
       
   253                     // at this code source URL.
       
   254                     if ((man != null) && isSealed(pkgname, man)) {
       
   255                         throw new SecurityException(
       
   256                             "sealing violation: can't seal package " + pkgname +
       
   257                             ": already loaded");
       
   258                     }
       
   259                 }
       
   260             } else {
       
   261                 if (man != null) {
       
   262                     definePackage(pkgname, man, url);
       
   263                 } else {
       
   264                     definePackage(pkgname, null, null, null, null, null, null, null);
       
   265                 }
       
   266             }
       
   267         }
       
   268         // Now read the class bytes and define the class
       
   269         java.nio.ByteBuffer bb = res.getByteBuffer();
       
   270         if (bb != null) {
       
   271             // Use (direct) ByteBuffer:
       
   272             CodeSigner[] signers = res.getCodeSigners();
       
   273             CodeSource cs = new CodeSource(url, signers);
       
   274             return defineClass(name, bb, cs);
       
   275         } else {
       
   276             byte[] b = res.getBytes();
       
   277             // must read certificates AFTER reading bytes.
       
   278             CodeSigner[] signers = res.getCodeSigners();
       
   279             CodeSource cs = new CodeSource(url, signers);
       
   280             return defineClass(name, b, 0, b.length, cs);
       
   281         }
       
   282     }
       
   283 
       
   284     /**
       
   285      * Defines a new package by name in this ClassLoader. The attributes
       
   286      * contained in the specified Manifest will be used to obtain package
       
   287      * version and sealing information. For sealed packages, the additional
       
   288      * URL specifies the code source URL from which the package was loaded.
       
   289      *
       
   290      * @param name  the package name
       
   291      * @param man   the Manifest containing package version and sealing
       
   292      *              information
       
   293      * @param url   the code source url for the package, or null if none
       
   294      * @exception   IllegalArgumentException if the package name duplicates
       
   295      *              an existing package either in this class loader or one
       
   296      *              of its ancestors
       
   297      * @return the newly defined Package object
       
   298      */
       
   299     protected Package definePackage(String name, Manifest man, URL url)
       
   300         throws IllegalArgumentException
       
   301     {
       
   302         String path = name.replace('.', '/').concat("/");
       
   303         String specTitle = null, specVersion = null, specVendor = null;
       
   304         String implTitle = null, implVersion = null, implVendor = null;
       
   305         String sealed = null;
       
   306         URL sealBase = null;
       
   307 
       
   308         Attributes attr = man.getAttributes(path);
       
   309         if (attr != null) {
       
   310             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
       
   311             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
       
   312             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
       
   313             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
       
   314             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
       
   315             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
       
   316             sealed      = attr.getValue(Name.SEALED);
       
   317         }
       
   318         attr = man.getMainAttributes();
       
   319         if (attr != null) {
       
   320             if (specTitle == null) {
       
   321                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
       
   322             }
       
   323             if (specVersion == null) {
       
   324                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
       
   325             }
       
   326             if (specVendor == null) {
       
   327                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
       
   328             }
       
   329             if (implTitle == null) {
       
   330                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
       
   331             }
       
   332             if (implVersion == null) {
       
   333                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
       
   334             }
       
   335             if (implVendor == null) {
       
   336                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
       
   337             }
       
   338             if (sealed == null) {
       
   339                 sealed = attr.getValue(Name.SEALED);
       
   340             }
       
   341         }
       
   342         if ("true".equalsIgnoreCase(sealed)) {
       
   343             sealBase = url;
       
   344         }
       
   345         return definePackage(name, specTitle, specVersion, specVendor,
       
   346                              implTitle, implVersion, implVendor, sealBase);
       
   347     }
       
   348 
       
   349     /*
       
   350      * Returns true if the specified package name is sealed according to the
       
   351      * given manifest.
       
   352      */
       
   353     private boolean isSealed(String name, Manifest man) {
       
   354         String path = name.replace('.', '/').concat("/");
       
   355         Attributes attr = man.getAttributes(path);
       
   356         String sealed = null;
       
   357         if (attr != null) {
       
   358             sealed = attr.getValue(Name.SEALED);
       
   359         }
       
   360         if (sealed == null) {
       
   361             if ((attr = man.getMainAttributes()) != null) {
       
   362                 sealed = attr.getValue(Name.SEALED);
       
   363             }
       
   364         }
       
   365         return "true".equalsIgnoreCase(sealed);
       
   366     }
       
   367 
       
   368     /**
       
   369      * Finds the resource with the specified name on the URL search path.
       
   370      *
       
   371      * @param name the name of the resource
       
   372      * @return a <code>URL</code> for the resource, or <code>null</code>
       
   373      * if the resource could not be found.
       
   374      */
       
   375     public URL findResource(final String name) {
       
   376         /*
       
   377          * The same restriction to finding classes applies to resources
       
   378          */
       
   379         URL url =
       
   380             (URL) AccessController.doPrivileged(new PrivilegedAction() {
       
   381                 public Object run() {
       
   382                     return ucp.findResource(name, true);
       
   383                 }
       
   384             }, acc);
       
   385 
       
   386         return url != null ? ucp.checkURL(url) : null;
       
   387     }
       
   388 
       
   389     /**
       
   390      * Returns an Enumeration of URLs representing all of the resources
       
   391      * on the URL search path having the specified name.
       
   392      *
       
   393      * @param name the resource name
       
   394      * @exception IOException if an I/O exception occurs
       
   395      * @return an <code>Enumeration</code> of <code>URL</code>s
       
   396      */
       
   397     public Enumeration<URL> findResources(final String name)
       
   398         throws IOException
       
   399     {
       
   400         final Enumeration e = ucp.findResources(name, true);
       
   401 
       
   402         return new Enumeration<URL>() {
       
   403             private URL url = null;
       
   404 
       
   405             private boolean next() {
       
   406                 if (url != null) {
       
   407                     return true;
       
   408                 }
       
   409                 do {
       
   410                     URL u = (URL)
       
   411                         AccessController.doPrivileged(new PrivilegedAction() {
       
   412                             public Object run() {
       
   413                                 if (!e.hasMoreElements())
       
   414                                     return null;
       
   415                                 return e.nextElement();
       
   416                             }
       
   417                         }, acc);
       
   418                     if (u == null)
       
   419                         break;
       
   420                     url = ucp.checkURL(u);
       
   421                 } while (url == null);
       
   422                 return url != null;
       
   423             }
       
   424 
       
   425             public URL nextElement() {
       
   426                 if (!next()) {
       
   427                     throw new NoSuchElementException();
       
   428                 }
       
   429                 URL u = url;
       
   430                 url = null;
       
   431                 return u;
       
   432             }
       
   433 
       
   434             public boolean hasMoreElements() {
       
   435                 return next();
       
   436             }
       
   437         };
       
   438     }
       
   439 
       
   440     /**
       
   441      * Returns the permissions for the given codesource object.
       
   442      * The implementation of this method first calls super.getPermissions
       
   443      * and then adds permissions based on the URL of the codesource.
       
   444      * <p>
       
   445      * If the protocol of this URL is "jar", then the permission granted
       
   446      * is based on the permission that is required by the URL of the Jar
       
   447      * file.
       
   448      * <p>
       
   449      * If the protocol is "file" and there is an authority component, then
       
   450      * permission to connect to and accept connections from that authority
       
   451      * may be granted. If the protocol is "file"
       
   452      * and the path specifies a file, then permission to read that
       
   453      * file is granted. If protocol is "file" and the path is
       
   454      * a directory, permission is granted to read all files
       
   455      * and (recursively) all files and subdirectories contained in
       
   456      * that directory.
       
   457      * <p>
       
   458      * If the protocol is not "file", then permission
       
   459      * to connect to and accept connections from the URL's host is granted.
       
   460      * @param codesource the codesource
       
   461      * @return the permissions granted to the codesource
       
   462      */
       
   463     protected PermissionCollection getPermissions(CodeSource codesource)
       
   464     {
       
   465         PermissionCollection perms = super.getPermissions(codesource);
       
   466 
       
   467         URL url = codesource.getLocation();
       
   468 
       
   469         Permission p;
       
   470         URLConnection urlConnection;
       
   471 
       
   472         try {
       
   473             urlConnection = url.openConnection();
       
   474             p = urlConnection.getPermission();
       
   475         } catch (java.io.IOException ioe) {
       
   476             p = null;
       
   477             urlConnection = null;
       
   478         }
       
   479 
       
   480         if (p instanceof FilePermission) {
       
   481             // if the permission has a separator char on the end,
       
   482             // it means the codebase is a directory, and we need
       
   483             // to add an additional permission to read recursively
       
   484             String path = p.getName();
       
   485             if (path.endsWith(File.separator)) {
       
   486                 path += "-";
       
   487                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
       
   488             }
       
   489         } else if ((p == null) && (url.getProtocol().equals("file"))) {
       
   490             String path = url.getFile().replace('/', File.separatorChar);
       
   491             path = ParseUtil.decode(path);
       
   492             if (path.endsWith(File.separator))
       
   493                 path += "-";
       
   494             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
       
   495         } else {
       
   496             /**
       
   497              * Not loading from a 'file:' URL so we want to give the class
       
   498              * permission to connect to and accept from the remote host
       
   499              * after we've made sure the host is the correct one and is valid.
       
   500              */
       
   501             URL locUrl = url;
       
   502             if (urlConnection instanceof JarURLConnection) {
       
   503                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
       
   504             }
       
   505             String host = locUrl.getHost();
       
   506             if (host != null && (host.length() > 0))
       
   507                 p = new SocketPermission(host,
       
   508                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
       
   509         }
       
   510 
       
   511         // make sure the person that created this class loader
       
   512         // would have this permission
       
   513 
       
   514         if (p != null) {
       
   515             final SecurityManager sm = System.getSecurityManager();
       
   516             if (sm != null) {
       
   517                 final Permission fp = p;
       
   518                 AccessController.doPrivileged(new PrivilegedAction() {
       
   519                     public Object run() throws SecurityException {
       
   520                         sm.checkPermission(fp);
       
   521                         return null;
       
   522                     }
       
   523                 }, acc);
       
   524             }
       
   525             perms.add(p);
       
   526         }
       
   527         return perms;
       
   528     }
       
   529 
       
   530     /**
       
   531      * Creates a new instance of URLClassLoader for the specified
       
   532      * URLs and parent class loader. If a security manager is
       
   533      * installed, the <code>loadClass</code> method of the URLClassLoader
       
   534      * returned by this method will invoke the
       
   535      * <code>SecurityManager.checkPackageAccess</code> method before
       
   536      * loading the class.
       
   537      *
       
   538      * @param urls the URLs to search for classes and resources
       
   539      * @param parent the parent class loader for delegation
       
   540      * @return the resulting class loader
       
   541      */
       
   542     public static URLClassLoader newInstance(final URL[] urls,
       
   543                                              final ClassLoader parent) {
       
   544         // Save the caller's context
       
   545         AccessControlContext acc = AccessController.getContext();
       
   546         // Need a privileged block to create the class loader
       
   547         URLClassLoader ucl =
       
   548             (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
       
   549                 public Object run() {
       
   550                     return new FactoryURLClassLoader(urls, parent);
       
   551                 }
       
   552             });
       
   553         // Now set the context on the loader using the one we saved,
       
   554         // not the one inside the privileged block...
       
   555         ucl.acc = acc;
       
   556         return ucl;
       
   557     }
       
   558 
       
   559     /**
       
   560      * Creates a new instance of URLClassLoader for the specified
       
   561      * URLs and default parent class loader. If a security manager is
       
   562      * installed, the <code>loadClass</code> method of the URLClassLoader
       
   563      * returned by this method will invoke the
       
   564      * <code>SecurityManager.checkPackageAccess</code> before
       
   565      * loading the class.
       
   566      *
       
   567      * @param urls the URLs to search for classes and resources
       
   568      * @return the resulting class loader
       
   569      */
       
   570     public static URLClassLoader newInstance(final URL[] urls) {
       
   571         // Save the caller's context
       
   572         AccessControlContext acc = AccessController.getContext();
       
   573         // Need a privileged block to create the class loader
       
   574         URLClassLoader ucl = (URLClassLoader)
       
   575             AccessController.doPrivileged(new PrivilegedAction() {
       
   576                 public Object run() {
       
   577                     return new FactoryURLClassLoader(urls);
       
   578                 }
       
   579             });
       
   580 
       
   581         // Now set the context on the loader using the one we saved,
       
   582         // not the one inside the privileged block...
       
   583         ucl.acc = acc;
       
   584         return ucl;
       
   585     }
       
   586 
       
   587     static {
       
   588         sun.misc.SharedSecrets.setJavaNetAccess (
       
   589             new sun.misc.JavaNetAccess() {
       
   590                 public URLClassPath getURLClassPath (URLClassLoader u) {
       
   591                     return u.ucp;
       
   592                 }
       
   593             }
       
   594         );
       
   595     }
       
   596 }
       
   597 
       
   598 final class FactoryURLClassLoader extends URLClassLoader {
       
   599 
       
   600     FactoryURLClassLoader(URL[] urls, ClassLoader parent) {
       
   601         super(urls, parent);
       
   602     }
       
   603 
       
   604     FactoryURLClassLoader(URL[] urls) {
       
   605         super(urls);
       
   606     }
       
   607 
       
   608     public final synchronized Class loadClass(String name, boolean resolve)
       
   609         throws ClassNotFoundException
       
   610     {
       
   611         // First check if we have permission to access the package. This
       
   612         // should go away once we've added support for exported packages.
       
   613         SecurityManager sm = System.getSecurityManager();
       
   614         if (sm != null) {
       
   615             int i = name.lastIndexOf('.');
       
   616             if (i != -1) {
       
   617                 sm.checkPackageAccess(name.substring(0, i));
       
   618             }
       
   619         }
       
   620         return super.loadClass(name, resolve);
       
   621     }
       
   622 }