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