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