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 */
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
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
442 return defineClass(name, bb, cs);
443 } else {
444 byte[] b = res.getBytes();
445 // must read certificates AFTER reading bytes.
446 CodeSigner[] signers = res.getCodeSigners();
447 CodeSource cs = new CodeSource(url, signers);
448 sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
449 return defineClass(name, b, 0, b.length, cs);
450 }
451 }
452
453 /**
454 * Defines a new package by name in this ClassLoader. The attributes
455 * contained in the specified Manifest will be used to obtain package
456 * version and sealing information. For sealed packages, the additional
457 * URL specifies the code source URL from which the package was loaded.
458 *
459 * @param name the package name
460 * @param man the Manifest containing package version and sealing
461 * information
462 * @param url the code source url for the package, or null if none
463 * @exception IllegalArgumentException if the package name duplicates
464 * an existing package either in this class loader or one
465 * of its ancestors
466 * @return the newly defined Package object
467 */
468 protected Package definePackage(String name, Manifest man, URL url)
469 throws IllegalArgumentException
470 {
471 String path = name.replace('.', '/').concat("/");
472 String specTitle = null, specVersion = null, specVendor = null;
473 String implTitle = null, implVersion = null, implVendor = null;
474 String sealed = null;
475 URL sealBase = null;
476
477 Attributes attr = man.getAttributes(path);
478 if (attr != null) {
479 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
480 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
481 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
482 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
483 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
484 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
485 sealed = attr.getValue(Name.SEALED);
486 }
487 attr = man.getMainAttributes();
488 if (attr != null) {
489 if (specTitle == null) {
490 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
491 }
492 if (specVersion == null) {
493 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
494 }
495 if (specVendor == null) {
496 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
497 }
498 if (implTitle == null) {
499 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
500 }
501 if (implVersion == null) {
502 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
503 }
504 if (implVendor == null) {
505 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
506 }
507 if (sealed == null) {
508 sealed = attr.getValue(Name.SEALED);
509 }
510 }
511 if ("true".equalsIgnoreCase(sealed)) {
512 sealBase = url;
513 }
514 return definePackage(name, specTitle, specVersion, specVendor,
515 implTitle, implVersion, implVendor, sealBase);
516 }
517
518 /*
519 * Returns true if the specified package name is sealed according to the
520 * given manifest.
521 */
522 private boolean isSealed(String name, Manifest man) {
523 String path = name.replace('.', '/').concat("/");
524 Attributes attr = man.getAttributes(path);
525 String sealed = null;
526 if (attr != null) {
527 sealed = attr.getValue(Name.SEALED);
528 }
529 if (sealed == null) {
530 if ((attr = man.getMainAttributes()) != null) {
531 sealed = attr.getValue(Name.SEALED);
532 }
533 }
534 return "true".equalsIgnoreCase(sealed);
535 }
536
537 /**
538 * Finds the resource with the specified name on the URL search path.
539 *
540 * @param name the name of the resource
541 * @return a <code>URL</code> for the resource, or <code>null</code>
542 * if the resource could not be found, or if the loader is closed.
543 */
544 public URL findResource(final String name) {
545 /*
546 * The same restriction to finding classes applies to resources
547 */
548 URL url = AccessController.doPrivileged(
549 new PrivilegedAction<URL>() {
550 public URL run() {
551 return ucp.findResource(name, true);
552 }
553 }, acc);
554
555 return url != null ? ucp.checkURL(url) : null;
556 }
557
558 /**
559 * Returns an Enumeration of URLs representing all of the resources
560 * on the URL search path having the specified name.
561 *
562 * @param name the resource name
563 * @exception IOException if an I/O exception occurs
564 * @return an <code>Enumeration</code> of <code>URL</code>s
565 * If the loader is closed, the Enumeration will be empty.
566 */
567 public Enumeration<URL> findResources(final String name)
568 throws IOException
569 {
570 final Enumeration<URL> e = ucp.findResources(name, true);
571
572 return new Enumeration<URL>() {
573 private URL url = null;
574
575 private boolean next() {
576 if (url != null) {
577 return true;
578 }
579 do {
580 URL u = AccessController.doPrivileged(
581 new PrivilegedAction<URL>() {
582 public URL run() {
583 if (!e.hasMoreElements())
584 return null;
585 return e.nextElement();
586 }
587 }, acc);
588 if (u == null)
589 break;
590 url = ucp.checkURL(u);
591 } while (url == null);
592 return url != null;
593 }
594
595 public URL nextElement() {
596 if (!next()) {
597 throw new NoSuchElementException();
598 }
599 URL u = url;
600 url = null;
601 return u;
602 }
603
604 public boolean hasMoreElements() {
605 return next();
606 }
607 };
608 }
609
610 /**
611 * Returns the permissions for the given codesource object.
612 * The implementation of this method first calls super.getPermissions
613 * and then adds permissions based on the URL of the codesource.
614 * <p>
615 * If the protocol of this URL is "jar", then the permission granted
616 * is based on the permission that is required by the URL of the Jar
617 * file.
618 * <p>
619 * If the protocol is "file" and there is an authority component, then
620 * permission to connect to and accept connections from that authority
621 * may be granted. If the protocol is "file"
622 * and the path specifies a file, then permission to read that
623 * file is granted. If protocol is "file" and the path is
624 * a directory, permission is granted to read all files
625 * and (recursively) all files and subdirectories contained in
626 * that directory.
627 * <p>
628 * If the protocol is not "file", then permission
629 * to connect to and accept connections from the URL's host is granted.
630 * @param codesource the codesource
631 * @return the permissions granted to the codesource
632 */
633 protected PermissionCollection getPermissions(CodeSource codesource)
634 {
635 PermissionCollection perms = super.getPermissions(codesource);
636
637 URL url = codesource.getLocation();
638
639 Permission p;
640 URLConnection urlConnection;
641
642 try {
643 urlConnection = url.openConnection();
644 p = urlConnection.getPermission();
645 } catch (java.io.IOException ioe) {
646 p = null;
647 urlConnection = null;
648 }
649
650 if (p instanceof FilePermission) {
651 // if the permission has a separator char on the end,
652 // it means the codebase is a directory, and we need
653 // to add an additional permission to read recursively
654 String path = p.getName();
655 if (path.endsWith(File.separator)) {
656 path += "-";
657 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
658 }
659 } else if ((p == null) && (url.getProtocol().equals("file"))) {
660 String path = url.getFile().replace('/', File.separatorChar);
661 path = ParseUtil.decode(path);
662 if (path.endsWith(File.separator))
663 path += "-";
664 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
665 } else {
666 /**
667 * Not loading from a 'file:' URL so we want to give the class
668 * permission to connect to and accept from the remote host
669 * after we've made sure the host is the correct one and is valid.
670 */
671 URL locUrl = url;
672 if (urlConnection instanceof JarURLConnection) {
673 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
674 }
675 String host = locUrl.getHost();
676 if (host != null && (host.length() > 0))
677 p = new SocketPermission(host,
678 SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
679 }
680
681 // make sure the person that created this class loader
682 // would have this permission
683
684 if (p != null) {
685 final SecurityManager sm = System.getSecurityManager();
686 if (sm != null) {
687 final Permission fp = p;
688 AccessController.doPrivileged(new PrivilegedAction<Void>() {
689 public Void run() throws SecurityException {
690 sm.checkPermission(fp);
691 return null;
692 }
693 }, acc);
694 }
695 perms.add(p);
696 }
697 return perms;
698 }
699
700 /**
701 * Creates a new instance of URLClassLoader for the specified
702 * URLs and parent class loader. If a security manager is
703 * installed, the <code>loadClass</code> method of the URLClassLoader
704 * returned by this method will invoke the
705 * <code>SecurityManager.checkPackageAccess</code> method before
706 * loading the class.
707 *
708 * @param urls the URLs to search for classes and resources
709 * @param parent the parent class loader for delegation
710 * @return the resulting class loader
711 */
712 public static URLClassLoader newInstance(final URL[] urls,
713 final ClassLoader parent) {
714 // Save the caller's context
715 final AccessControlContext acc = AccessController.getContext();
716 // Need a privileged block to create the class loader
717 URLClassLoader ucl = AccessController.doPrivileged(
718 new PrivilegedAction<URLClassLoader>() {
719 public URLClassLoader run() {
720 return new FactoryURLClassLoader(urls, parent, acc);
721 }
722 });
723 return ucl;
724 }
725
726 /**
727 * Creates a new instance of URLClassLoader for the specified
728 * URLs and default parent class loader. If a security manager is
729 * installed, the <code>loadClass</code> method of the URLClassLoader
730 * returned by this method will invoke the
731 * <code>SecurityManager.checkPackageAccess</code> before
732 * loading the class.
733 *
734 * @param urls the URLs to search for classes and resources
735 * @return the resulting class loader
736 */
737 public static URLClassLoader newInstance(final URL[] urls) {
738 // Save the caller's context
739 final AccessControlContext acc = AccessController.getContext();
740 // Need a privileged block to create the class loader
741 URLClassLoader ucl = AccessController.doPrivileged(
742 new PrivilegedAction<URLClassLoader>() {
743 public URLClassLoader run() {
744 return new FactoryURLClassLoader(urls, acc);
745 }
746 });
747 return ucl;
748 }
749
750 static {
751 sun.misc.SharedSecrets.setJavaNetAccess (
752 new sun.misc.JavaNetAccess() {
753 public URLClassPath getURLClassPath (URLClassLoader u) {
754 return u.ucp;
755 }
756 }
757 );
758 ClassLoader.registerAsParallelCapable();
759 }
760 }
761
762 final class FactoryURLClassLoader extends URLClassLoader {
763
764 static {
765 ClassLoader.registerAsParallelCapable();
766 }
767
768 FactoryURLClassLoader(URL[] urls, ClassLoader parent,
769 AccessControlContext acc) {
770 super(urls, parent, acc);
771 }
772
773 FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
774 super(urls, acc);
775 }
776
777 public final Class loadClass(String name, boolean resolve)
778 throws ClassNotFoundException
779 {
780 // First check if we have permission to access the package. This
781 // should go away once we've added support for exported packages.
782 SecurityManager sm = System.getSecurityManager();
783 if (sm != null) {
784 int i = name.lastIndexOf('.');
785 if (i != -1) {
786 sm.checkPackageAccess(name.substring(0, i));
787 }
788 }
789 return super.loadClass(name, resolve);
790 }
791 }