1 /*
2  * Copyright (c) 1997, 2017, 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
53 import jdk.internal.loader.Resource;
54 import jdk.internal.loader.URLClassPath;
55 import jdk.internal.misc.JavaNetURLClassLoaderAccess;
56 import jdk.internal.misc.SharedSecrets;
57 import jdk.internal.perf.PerfCounter;
58 import sun.net.www.ParseUtil;
59 import sun.security.util.SecurityConstants;
60
61 /**
62  * This class loader is used to load classes and resources from a search
63  * path of URLs referring to both JAR files and directories. Any {@code jar:}
64  * scheme URL (see {@link java.net.JarURLConnection}) is assumed to refer to a
65  * JAR file.  Any {@code file:} scheme URL that ends with a '/' is assumed to
66  * refer to a directory. Otherwise, the URL is assumed to refer to a JAR file
67  * which will be opened as needed.
68  * <p>
69  * This class loader supports the loading of classes and resources from the
70  * contents of a <a href="../util/jar/JarFile.html#multirelease">multi-release</a>
71  * JAR file that is referred to by a given URL.
72  * <p>
73  * The AccessControlContext of the thread that created the instance of
74  * URLClassLoader will be used when subsequently loading classes and
75  * resources.
76  * <p>
77  * The classes that are loaded are by default granted permission only to
78  * access the URLs specified when the URLClassLoader was created.
79  *
80  * @author  David Connelly
81  * @since   1.2
82  */

83 public class URLClassLoader extends SecureClassLoader implements Closeable {
84     /* The search path for classes and resources */
85     private final URLClassPath ucp;
86
87     /* The context to be used when loading classes and resources */
88     private final AccessControlContext acc;
89
90     /**
91      * Constructs a new URLClassLoader for the given URLs. The URLs will be
92      * searched in the order specified for classes and resources after first
93      * searching in the specified parent class loader.  Any {@code jar:}
94      * scheme URL is assumed to refer to a JAR file.  Any {@code file:} scheme
95      * URL that ends with a '/' is assumed to refer to a directory.  Otherwise,
96      * the URL is assumed to refer to a JAR file which will be downloaded and
97      * opened as needed.
98      *
99      * <p>If there is a security manager, this method first
100      * calls the security manager's {@code checkCreateClassLoader} method
101      * to ensure creation of a class loader is allowed.
102      *
103      * @param urls the URLs from which to load classes and resources
104      * @param parent the parent class loader for delegation
105      * @exception  SecurityException  if a security manager exists and its
106      *             {@code checkCreateClassLoader} method doesn't allow
107      *             creation of a class loader.
108      * @exception  NullPointerException if {@code urls} or any of its
109      *             elements is {@code null}.
110      * @see SecurityManager#checkCreateClassLoader
111      */

112     public URLClassLoader(URL[] urls, ClassLoader parent) {
113         super(parent);
114         // this is to make the stack depth consistent with 1.1
115         SecurityManager security = System.getSecurityManager();
116         if (security != null) {
117             security.checkCreateClassLoader();
118         }
119         this.acc = AccessController.getContext();
120         this.ucp = new URLClassPath(urls, acc);
121     }
122
123     URLClassLoader(String name, URL[] urls, ClassLoader parent,
124                    AccessControlContext acc) {
125         super(name, parent);
126         // this is to make the stack depth consistent with 1.1
127         SecurityManager security = System.getSecurityManager();
128         if (security != null) {
129             security.checkCreateClassLoader();
130         }
131         this.acc = acc;
132         this.ucp = new URLClassPath(urls, acc);
133     }
134
135     /**
136      * Constructs a new URLClassLoader for the specified URLs using the
137      * default delegation parent {@code ClassLoader}. The URLs will
138      * be searched in the order specified for classes and resources after
139      * first searching in the parent class loader. Any URL that ends with
140      * a '/' is assumed to refer to a directory. Otherwise, the URL is
141      * assumed to refer to a JAR file which will be downloaded and opened
142      * as needed.
143      *
144      * <p>If there is a security manager, this method first
145      * calls the security manager's {@code checkCreateClassLoader} method
146      * to ensure creation of a class loader is allowed.
147      *
148      * @param urls the URLs from which to load classes and resources
149      *
150      * @exception  SecurityException  if a security manager exists and its
151      *             {@code checkCreateClassLoader} method doesn't allow
152      *             creation of a class loader.
153      * @exception  NullPointerException if {@code urls} or any of its
154      *             elements is {@code null}.
155      * @see SecurityManager#checkCreateClassLoader
156      */

157     public URLClassLoader(URL[] urls) {
158         super();
159         // this is to make the stack depth consistent with 1.1
160         SecurityManager security = System.getSecurityManager();
161         if (security != null) {
162             security.checkCreateClassLoader();
163         }
164         this.acc = AccessController.getContext();
165         this.ucp = new URLClassPath(urls, acc);
166     }
167
168     URLClassLoader(URL[] urls, AccessControlContext acc) {
169         super();
170         // this is to make the stack depth consistent with 1.1
171         SecurityManager security = System.getSecurityManager();
172         if (security != null) {
173             security.checkCreateClassLoader();
174         }
175         this.acc = acc;
176         this.ucp = new URLClassPath(urls, acc);
177     }
178
179     /**
180      * Constructs a new URLClassLoader for the specified URLs, parent
181      * class loader, and URLStreamHandlerFactory. The parent argument
182      * will be used as the parent class loader for delegation. The
183      * factory argument will be used as the stream handler factory to
184      * obtain protocol handlers when creating new jar URLs.
185      *
186      * <p>If there is a security manager, this method first
187      * calls the security manager's {@code checkCreateClassLoader} method
188      * to ensure creation of a class loader is allowed.
189      *
190      * @param urls the URLs from which to load classes and resources
191      * @param parent the parent class loader for delegation
192      * @param factory the URLStreamHandlerFactory to use when creating URLs
193      *
194      * @exception  SecurityException  if a security manager exists and its
195      *             {@code checkCreateClassLoader} method doesn't allow
196      *             creation of a class loader.
197      * @exception  NullPointerException if {@code urls} or any of its
198      *             elements is {@code null}.
199      * @see SecurityManager#checkCreateClassLoader
200      */

201     public URLClassLoader(URL[] urls, ClassLoader parent,
202                           URLStreamHandlerFactory factory) {
203         super(parent);
204         // this is to make the stack depth consistent with 1.1
205         SecurityManager security = System.getSecurityManager();
206         if (security != null) {
207             security.checkCreateClassLoader();
208         }
209         this.acc = AccessController.getContext();
210         this.ucp = new URLClassPath(urls, factory, acc);
211     }
212
213
214     /**
215      * Constructs a new named {@code URLClassLoader} for the specified URLs.
216      * The URLs will be searched in the order specified for classes
217      * and resources after first searching in the specified parent class loader.
218      * Any URL that ends with a '/' is assumed to refer to a directory.
219      * Otherwise, the URL is assumed to refer to a JAR file which will be
220      * downloaded and opened as needed.
221      *
222      * @param  name class loader name; or {@code nullif not named
223      * @param  urls the URLs from which to load classes and resources
224      * @param  parent the parent class loader for delegation
225      *
226      * @throws IllegalArgumentException if the given name is empty.
227      * @throws NullPointerException if {@code urls} or any of its
228      *         elements is {@code null}.
229      *
230      * @throws SecurityException if a security manager exists and its
231      *         {@link SecurityManager#checkCreateClassLoader()} method doesn't
232      *         allow creation of a class loader.
233      *
234      * @since 9
235      * @spec JPMS
236      */

237     public URLClassLoader(String name,
238                           URL[] urls,
239                           ClassLoader parent) {
240         super(name, parent);
241         // this is to make the stack depth consistent with 1.1
242         SecurityManager security = System.getSecurityManager();
243         if (security != null) {
244             security.checkCreateClassLoader();
245         }
246         this.acc = AccessController.getContext();
247         this.ucp = new URLClassPath(urls, acc);
248     }
249
250     /**
251      * Constructs a new named {@code URLClassLoader} for the specified URLs,
252      * parent class loader, and URLStreamHandlerFactory.
253      * The parent argument will be used as the parent class loader for delegation.
254      * The factory argument will be used as the stream handler factory to
255      * obtain protocol handlers when creating new jar URLs.
256      *
257      * @param  name class loader name; or {@code nullif not named
258      * @param  urls the URLs from which to load classes and resources
259      * @param  parent the parent class loader for delegation
260      * @param  factory the URLStreamHandlerFactory to use when creating URLs
261      *
262      * @throws IllegalArgumentException if the given name is empty.
263      * @throws NullPointerException if {@code urls} or any of its
264      *         elements is {@code null}.
265      *
266      * @throws SecurityException if a security manager exists and its
267      *         {@code checkCreateClassLoader} method doesn't allow
268      *         creation of a class loader.
269      *
270      * @since 9
271      * @spec JPMS
272      */

273     public URLClassLoader(String name, URL[] urls, ClassLoader parent,
274                           URLStreamHandlerFactory factory) {
275         super(name, parent);
276         // this is to make the stack depth consistent with 1.1
277         SecurityManager security = System.getSecurityManager();
278         if (security != null) {
279             security.checkCreateClassLoader();
280         }
281         this.acc = AccessController.getContext();
282         this.ucp = new URLClassPath(urls, factory, acc);
283     }
284
285     /* A map (used as a set) to keep track of closeable local resources
286      * (either JarFiles or FileInputStreams). We don't care about
287      * Http resources since they don't need to be closed.
288      *
289      * If the resource is coming from a jar file
290      * we keep a (weak) reference to the JarFile object which can
291      * be closed if URLClassLoader.close() called. Due to jar file
292      * caching there will typically be only one JarFile object
293      * per underlying jar file.
294      *
295      * For file resources, which is probably a less common situation
296      * we have to keep a weak reference to each stream.
297      */

298
299     private WeakHashMap<Closeable,Void>
300         closeables = new WeakHashMap<>();
301
302     /**
303      * Returns an input stream for reading the specified resource.
304      * If this loader is closed, then any resources opened by this method
305      * will be closed.
306      *
307      * <p> The search order is described in the documentation for {@link
308      * #getResource(String)}.  </p>
309      *
310      * @param  name
311      *         The resource name
312      *
313      * @return  An input stream for reading the resource, or {@code null}
314      *          if the resource could not be found
315      *
316      * @throws  NullPointerException If {@code name} is {@code null}
317      *
318      * @since  1.7
319      */

320     public InputStream getResourceAsStream(String name) {
321         Objects.requireNonNull(name);
322         URL url = getResource(name);
323         try {
324             if (url == null) {
325                 return null;
326             }
327             URLConnection urlc = url.openConnection();
328             InputStream is = urlc.getInputStream();
329             if (urlc instanceof JarURLConnection) {
330                 JarURLConnection juc = (JarURLConnection)urlc;
331                 JarFile jar = juc.getJarFile();
332                 synchronized (closeables) {
333                     if (!closeables.containsKey(jar)) {
334                         closeables.put(jar, null);
335                     }
336                 }
337             } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
338                 synchronized (closeables) {
339                     closeables.put(is, null);
340                 }
341             }
342             return is;
343         } catch (IOException e) {
344             return null;
345         }
346     }
347
348    /**
349     * Closes this URLClassLoader, so that it can no longer be used to load
350     * new classes or resources that are defined by this loader.
351     * Classes and resources defined by any of this loader's parents in the
352     * delegation hierarchy are still accessible. Also, any classes or resources
353     * that are already loaded, are still accessible.
354     * <p>
355     * In the case of jar: and file: URLs, it also closes any files
356     * that were opened by it. If another thread is loading a
357     * class when the {@code close} method is invoked, then the result of
358     * that load is undefined.
359     * <p>
360     * The method makes a best effort attempt to close all opened files,
361     * by catching {@link IOException}s internally. Unchecked exceptions
362     * and errors are not caught. Calling close on an already closed
363     * loader has no effect.
364     *
365     * @exception IOException if closing any file opened by this class loader
366     * resulted in an IOException. Any such exceptions are caught internally.
367     * If only one is caught, then it is re-thrown. If more than one exception
368     * is caught, then the second and following exceptions are added
369     * as suppressed exceptions of the first one caught, which is then re-thrown.
370     *
371     * @exception SecurityException if a security manager is set, and it denies
372     *   {@link RuntimePermission}{@code ("closeClassLoader")}
373     *
374     * @since 1.7
375     */

376     public void close() throws IOException {
377         SecurityManager security = System.getSecurityManager();
378         if (security != null) {
379             security.checkPermission(new RuntimePermission("closeClassLoader"));
380         }
381         List<IOException> errors = ucp.closeLoaders();
382
383         // now close any remaining streams.
384
385         synchronized (closeables) {
386             Set<Closeable> keys = closeables.keySet();
387             for (Closeable c : keys) {
388                 try {
389                     c.close();
390                 } catch (IOException ioex) {
391                     errors.add(ioex);
392                 }
393             }
394             closeables.clear();
395         }
396
397         if (errors.isEmpty()) {
398             return;
399         }
400
401         IOException firstex = errors.remove(0);
402
403         // Suppress any remaining exceptions
404
405         for (IOException error: errors) {
406             firstex.addSuppressed(error);
407         }
408         throw firstex;
409     }
410
411     /**
412      * Appends the specified URL to the list of URLs to search for
413      * classes and resources.
414      * <p>
415      * If the URL specified is {@code null} or is already in the
416      * list of URLs, or if this loader is closed, then invoking this
417      * method has no effect.
418      *
419      * @param url the URL to be added to the search path of URLs
420      */

421     protected void addURL(URL url) {
422         ucp.addURL(url);
423     }
424
425     /**
426      * Returns the search path of URLs for loading classes and resources.
427      * This includes the original list of URLs specified to the constructor,
428      * along with any URLs subsequently appended by the addURL() method.
429      * @return the search path of URLs for loading classes and resources.
430      */

431     public URL[] getURLs() {
432         return ucp.getURLs();
433     }
434
435     /**
436      * Finds and loads the class with the specified name from the URL search
437      * path. Any URLs referring to JAR files are loaded and opened as needed
438      * until the class is found.
439      *
440      * @param name the name of the class
441      * @return the resulting class
442      * @exception ClassNotFoundException if the class could not be found,
443      *            or if the loader is closed.
444      * @exception NullPointerException if {@code name} is {@code null}.
445      */

446     protected Class<?> findClass(final String name)
447         throws ClassNotFoundException
448     {
449         final Class<?> result;
450         try {
451             result = AccessController.doPrivileged(
452                 new PrivilegedExceptionAction<>() {
453                     public Class<?> run() throws ClassNotFoundException {
454                         String path = name.replace('.', '/').concat(".class");
455                         Resource res = ucp.getResource(path, false);
456                         if (res != null) {
457                             try {
458                                 return defineClass(name, res);
459                             } catch (IOException e) {
460                                 throw new ClassNotFoundException(name, e);
461                             }
462                         } else {
463                             return null;
464                         }
465                     }
466                 }, acc);
467         } catch (java.security.PrivilegedActionException pae) {
468             throw (ClassNotFoundException) pae.getException();
469         }
470         if (result == null) {
471             throw new ClassNotFoundException(name);
472         }
473         return result;
474     }
475
476     /*
477      * Retrieve the package using the specified package name.
478      * If non-null, verify the package using the specified code
479      * source and manifest.
480      */

481     private Package getAndVerifyPackage(String pkgname,
482                                         Manifest man, URL url) {
483         Package pkg = getDefinedPackage(pkgname);
484         if (pkg != null) {
485             // Package found, so check package sealing.
486             if (pkg.isSealed()) {
487                 // Verify that code source URL is the same.
488                 if (!pkg.isSealed(url)) {
489                     throw new SecurityException(
490                         "sealing violation: package " + pkgname + " is sealed");
491                 }
492             } else {
493                 // Make sure we are not attempting to seal the package
494                 // at this code source URL.
495                 if ((man != null) && isSealed(pkgname, man)) {
496                     throw new SecurityException(
497                         "sealing violation: can't seal package " + pkgname +
498                         ": already loaded");
499                 }
500             }
501         }
502         return pkg;
503     }
504
505     /*
506      * Defines a Class using the class bytes obtained from the specified
507      * Resource. The resulting Class must be resolved before it can be
508      * used.
509      */

510     private Class<?> defineClass(String name, Resource res) throws IOException {
511         long t0 = System.nanoTime();
512         int i = name.lastIndexOf('.');
513         URL url = res.getCodeSourceURL();
514         if (i != -1) {
515             String pkgname = name.substring(0, i);
516             // Check if package already loaded.
517             Manifest man = res.getManifest();
518             if (getAndVerifyPackage(pkgname, man, url) == null) {
519                 try {
520                     if (man != null) {
521                         definePackage(pkgname, man, url);
522                     } else {
523                         definePackage(pkgname, nullnullnullnullnullnullnull);
524                     }
525                 } catch (IllegalArgumentException iae) {
526                     // parallel-capable class loaders: re-verify in case of a
527                     // race condition
528                     if (getAndVerifyPackage(pkgname, man, url) == null) {
529                         // Should never happen
530                         throw new AssertionError("Cannot find package " +
531                                                  pkgname);
532                     }
533                 }
534             }
535         }
536         // Now read the class bytes and define the class
537         java.nio.ByteBuffer bb = res.getByteBuffer();
538         if (bb != null) {
539             // Use (direct) ByteBuffer:
540             CodeSigner[] signers = res.getCodeSigners();
541             CodeSource cs = new CodeSource(url, signers);
542             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
543             return defineClass(name, bb, cs);
544         } else {
545             byte[] b = res.getBytes();
546             // must read certificates AFTER reading bytes.
547             CodeSigner[] signers = res.getCodeSigners();
548             CodeSource cs = new CodeSource(url, signers);
549             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
550             return defineClass(name, b, 0, b.length, cs);
551         }
552     }
553
554     /**
555      * Defines a new package by name in this {@code URLClassLoader}.
556      * The attributes contained in the specified {@code Manifest}
557      * will be used to obtain package version and sealing information.
558      * For sealed packages, the additional URL specifies the code source URL
559      * from which the package was loaded.
560      *
561      * @param name  the package name
562      * @param man   the {@code Manifest} containing package version and sealing
563      *              information
564      * @param url   the code source url for the package, or null if none
565      * @throws      IllegalArgumentException if the package name is
566      *              already defined by this class loader
567      * @return      the newly defined {@code Package} object
568      *
569      * @revised 9
570      * @spec JPMS
571      */

572     protected Package definePackage(String name, Manifest man, URL url) {
573         String specTitle = null, specVersion = null, specVendor = null;
574         String implTitle = null, implVersion = null, implVendor = null;
575         String sealed = null;
576         URL sealBase = null;
577
578         Attributes attr = SharedSecrets.javaUtilJarAccess()
579                 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
580         if (attr != null) {
581             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
582             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
583             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
584             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
585             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
586             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
587             sealed      = attr.getValue(Name.SEALED);
588         }
589         attr = man.getMainAttributes();
590         if (attr != null) {
591             if (specTitle == null) {
592                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
593             }
594             if (specVersion == null) {
595                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
596             }
597             if (specVendor == null) {
598                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
599             }
600             if (implTitle == null) {
601                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
602             }
603             if (implVersion == null) {
604                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
605             }
606             if (implVendor == null) {
607                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
608             }
609             if (sealed == null) {
610                 sealed = attr.getValue(Name.SEALED);
611             }
612         }
613         if ("true".equalsIgnoreCase(sealed)) {
614             sealBase = url;
615         }
616         return definePackage(name, specTitle, specVersion, specVendor,
617                              implTitle, implVersion, implVendor, sealBase);
618     }
619
620     /*
621      * Returns true if the specified package name is sealed according to the
622      * given manifest.
623      *
624      * @throws SecurityException if the package name is untrusted in the manifest
625      */

626     private boolean isSealed(String name, Manifest man) {
627         Attributes attr = SharedSecrets.javaUtilJarAccess()
628                 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
629         String sealed = null;
630         if (attr != null) {
631             sealed = attr.getValue(Name.SEALED);
632         }
633         if (sealed == null) {
634             if ((attr = man.getMainAttributes()) != null) {
635                 sealed = attr.getValue(Name.SEALED);
636             }
637         }
638         return "true".equalsIgnoreCase(sealed);
639     }
640
641     /**
642      * Finds the resource with the specified name on the URL search path.
643      *
644      * @param name the name of the resource
645      * @return a {@code URL} for the resource, or {@code null}
646      * if the resource could not be found, or if the loader is closed.
647      */

648     public URL findResource(final String name) {
649         /*
650          * The same restriction to finding classes applies to resources
651          */

652         URL url = AccessController.doPrivileged(
653             new PrivilegedAction<>() {
654                 public URL run() {
655                     return ucp.findResource(name, true);
656                 }
657             }, acc);
658
659         return url != null ? URLClassPath.checkURL(url) : null;
660     }
661
662     /**
663      * Returns an Enumeration of URLs representing all of the resources
664      * on the URL search path having the specified name.
665      *
666      * @param name the resource name
667      * @exception IOException if an I/O exception occurs
668      * @return An {@code Enumeration} of {@code URL}s.
669      *         If the loader is closed, the Enumeration contains no elements.
670      */

671     public Enumeration<URL> findResources(final String name)
672         throws IOException
673     {
674         final Enumeration<URL> e = ucp.findResources(name, true);
675
676         return new Enumeration<>() {
677             private URL url = null;
678
679             private boolean next() {
680                 if (url != null) {
681                     return true;
682                 }
683                 do {
684                     URL u = AccessController.doPrivileged(
685                         new PrivilegedAction<>() {
686                             public URL run() {
687                                 if (!e.hasMoreElements())
688                                     return null;
689                                 return e.nextElement();
690                             }
691                         }, acc);
692                     if (u == null)
693                         break;
694                     url = URLClassPath.checkURL(u);
695                 } while (url == null);
696                 return url != null;
697             }
698
699             public URL nextElement() {
700                 if (!next()) {
701                     throw new NoSuchElementException();
702                 }
703                 URL u = url;
704                 url = null;
705                 return u;
706             }
707
708             public boolean hasMoreElements() {
709                 return next();
710             }
711         };
712     }
713
714     /**
715      * Returns the permissions for the given codesource object.
716      * The implementation of this method first calls super.getPermissions
717      * and then adds permissions based on the URL of the codesource.
718      * <p>
719      * If the protocol of this URL is "jar", then the permission granted
720      * is based on the permission that is required by the URL of the Jar
721      * file.
722      * <p>
723      * If the protocol is "file" and there is an authority component, then
724      * permission to connect to and accept connections from that authority
725      * may be granted. If the protocol is "file"
726      * and the path specifies a file, then permission to read that
727      * file is granted. If protocol is "file" and the path is
728      * a directory, permission is granted to read all files
729      * and (recursively) all files and subdirectories contained in
730      * that directory.
731      * <p>
732      * If the protocol is not "file", then permission
733      * to connect to and accept connections from the URL's host is granted.
734      * @param codesource the codesource
735      * @exception NullPointerException if {@code codesource} is {@code null}.
736      * @return the permissions granted to the codesource
737      */

738     protected PermissionCollection getPermissions(CodeSource codesource)
739     {
740         PermissionCollection perms = super.getPermissions(codesource);
741
742         URL url = codesource.getLocation();
743
744         Permission p;
745         URLConnection urlConnection;
746
747         try {
748             urlConnection = url.openConnection();
749             p = urlConnection.getPermission();
750         } catch (java.io.IOException ioe) {
751             p = null;
752             urlConnection = null;
753         }
754
755         if (p instanceof FilePermission) {
756             // if the permission has a separator char on the end,
757             // it means the codebase is a directory, and we need
758             // to add an additional permission to read recursively
759             String path = p.getName();
760             if (path.endsWith(File.separator)) {
761                 path += "-";
762                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
763             }
764         } else if ((p == null) && (url.getProtocol().equals("file"))) {
765             String path = url.getFile().replace('/', File.separatorChar);
766             path = ParseUtil.decode(path);
767             if (path.endsWith(File.separator))
768                 path += "-";
769             p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
770         } else {
771             /**
772              * Not loading from a 'file:' URL so we want to give the class
773              * permission to connect to and accept from the remote host
774              * after we've made sure the host is the correct one and is valid.
775              */

776             URL locUrl = url;
777             if (urlConnection instanceof JarURLConnection) {
778                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
779             }
780             String host = locUrl.getHost();
781             if (host != null && !host.isEmpty())
782                 p = new SocketPermission(host,
783                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
784         }
785
786         // make sure the person that created this class loader
787         // would have this permission
788
789         if (p != null) {
790             final SecurityManager sm = System.getSecurityManager();
791             if (sm != null) {
792                 final Permission fp = p;
793                 AccessController.doPrivileged(new PrivilegedAction<>() {
794                     public Void run() throws SecurityException {
795                         sm.checkPermission(fp);
796                         return null;
797                     }
798                 }, acc);
799             }
800             perms.add(p);
801         }
802         return perms;
803     }
804
805     /**
806      * Creates a new instance of URLClassLoader for the specified
807      * URLs and parent class loader. If a security manager is
808      * installed, the {@code loadClass} method of the URLClassLoader
809      * returned by this method will invoke the
810      * {@code SecurityManager.checkPackageAccess} method before
811      * loading the class.
812      *
813      * @param urls the URLs to search for classes and resources
814      * @param parent the parent class loader for delegation
815      * @exception  NullPointerException if {@code urls} or any of its
816      *             elements is {@code null}.
817      * @return the resulting class loader
818      */

819     public static URLClassLoader newInstance(final URL[] urls,
820                                              final ClassLoader parent) {
821         // Save the caller's context
822         final AccessControlContext acc = AccessController.getContext();
823         // Need a privileged block to create the class loader
824         URLClassLoader ucl = AccessController.doPrivileged(
825             new PrivilegedAction<>() {
826                 public URLClassLoader run() {
827                     return new FactoryURLClassLoader(null, urls, parent, acc);
828                 }
829             });
830         return ucl;
831     }
832
833     /**
834      * Creates a new instance of URLClassLoader for the specified
835      * URLs and default parent class loader. If a security manager is
836      * installed, the {@code loadClass} method of the URLClassLoader
837      * returned by this method will invoke the
838      * {@code SecurityManager.checkPackageAccess} before
839      * loading the class.
840      *
841      * @param urls the URLs to search for classes and resources
842      * @exception  NullPointerException if {@code urls} or any of its
843      *             elements is {@code null}.
844      * @return the resulting class loader
845      */

846     public static URLClassLoader newInstance(final URL[] urls) {
847         // Save the caller's context
848         final AccessControlContext acc = AccessController.getContext();
849         // Need a privileged block to create the class loader
850         URLClassLoader ucl = AccessController.doPrivileged(
851             new PrivilegedAction<>() {
852                 public URLClassLoader run() {
853                     return new FactoryURLClassLoader(urls, acc);
854                 }
855             });
856         return ucl;
857     }
858
859     static {
860         SharedSecrets.setJavaNetURLClassLoaderAccess(
861             new JavaNetURLClassLoaderAccess() {
862                 @Override
863                 public AccessControlContext getAccessControlContext(URLClassLoader u) {
864                     return u.acc;
865                 }
866             }
867         );
868         ClassLoader.registerAsParallelCapable();
869     }
870 }
871
872 final class FactoryURLClassLoader extends URLClassLoader {
873
874     static {
875         ClassLoader.registerAsParallelCapable();
876     }
877
878     FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent,
879                           AccessControlContext acc) {
880         super(name, urls, parent, acc);
881     }
882
883     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
884         super(urls, acc);
885     }
886
887     public final Class<?> loadClass(String name, boolean resolve)
888         throws ClassNotFoundException
889     {
890         // First check if we have permission to access the package. This
891         // should go away once we've added support for exported packages.
892         SecurityManager sm = System.getSecurityManager();
893         if (sm != null) {
894             int i = name.lastIndexOf('.');
895             if (i != -1) {
896                 sm.checkPackageAccess(name.substring(0, i));
897             }
898         }
899         return super.loadClass(name, resolve);
900     }
901 }
902