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