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