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