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