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