BuiltinClassLoader.java revision 17234:f8b19df2115a
1/* 2 * Copyright (c) 2015, 2016, 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 26package jdk.internal.loader; 27 28import java.io.File; 29import java.io.FilePermission; 30import java.io.IOException; 31import java.io.InputStream; 32import java.lang.module.ModuleDescriptor; 33import java.lang.module.ModuleReference; 34import java.lang.module.ModuleReader; 35import java.lang.ref.SoftReference; 36import java.net.MalformedURLException; 37import java.net.URI; 38import java.net.URL; 39import java.nio.ByteBuffer; 40import java.security.AccessController; 41import java.security.CodeSigner; 42import java.security.CodeSource; 43import java.security.Permission; 44import java.security.PermissionCollection; 45import java.security.PrivilegedAction; 46import java.security.PrivilegedActionException; 47import java.security.PrivilegedExceptionAction; 48import java.security.SecureClassLoader; 49import java.util.ArrayList; 50import java.util.Collections; 51import java.util.Enumeration; 52import java.util.Iterator; 53import java.util.List; 54import java.util.Map; 55import java.util.NoSuchElementException; 56import java.util.Optional; 57import java.util.concurrent.ConcurrentHashMap; 58import java.util.jar.Attributes; 59import java.util.jar.Manifest; 60import java.util.stream.Stream; 61 62import jdk.internal.misc.VM; 63import jdk.internal.module.ModulePatcher.PatchedModuleReader; 64import jdk.internal.module.SystemModules; 65import jdk.internal.module.Resources; 66 67 68/** 69 * The platform or application class loader. Resources loaded from modules 70 * defined to the boot class loader are also loaded via an instance of this 71 * ClassLoader type. 72 * 73 * <p> This ClassLoader supports loading of classes and resources from modules. 74 * Modules are defined to the ClassLoader by invoking the {@link #loadModule} 75 * method. Defining a module to this ClassLoader has the effect of making the 76 * types in the module visible. </p> 77 * 78 * <p> This ClassLoader also supports loading of classes and resources from a 79 * class path of URLs that are specified to the ClassLoader at construction 80 * time. The class path may expand at runtime (the Class-Path attribute in JAR 81 * files or via instrumentation agents). </p> 82 * 83 * <p> The delegation model used by this ClassLoader differs to the regular 84 * delegation model. When requested to load a class then this ClassLoader first 85 * maps the class name to its package name. If there is a module defined to a 86 * BuiltinClassLoader containing this package then the class loader delegates 87 * directly to that class loader. If there isn't a module containing the 88 * package then it delegates the search to the parent class loader and if not 89 * found in the parent then it searches the class path. The main difference 90 * between this and the usual delegation model is that it allows the platform 91 * class loader to delegate to the application class loader, important with 92 * upgraded modules defined to the platform class loader. 93 */ 94 95public class BuiltinClassLoader 96 extends SecureClassLoader 97{ 98 static { 99 if (!ClassLoader.registerAsParallelCapable()) 100 throw new InternalError("Unable to register as parallel capable"); 101 } 102 103 // parent ClassLoader 104 private final BuiltinClassLoader parent; 105 106 // the URL class path or null if there is no class path 107 private final URLClassPath ucp; 108 109 110 /** 111 * A module defined/loaded by a built-in class loader. 112 * 113 * A LoadedModule encapsulates a ModuleReference along with its CodeSource 114 * URL to avoid needing to create this URL when defining classes. 115 */ 116 private static class LoadedModule { 117 private final BuiltinClassLoader loader; 118 private final ModuleReference mref; 119 private final URL codeSourceURL; // may be null 120 121 LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { 122 URL url = null; 123 if (mref.location().isPresent()) { 124 try { 125 url = mref.location().get().toURL(); 126 } catch (MalformedURLException | IllegalArgumentException e) { } 127 } 128 this.loader = loader; 129 this.mref = mref; 130 this.codeSourceURL = url; 131 } 132 133 BuiltinClassLoader loader() { return loader; } 134 ModuleReference mref() { return mref; } 135 String name() { return mref.descriptor().name(); } 136 URL codeSourceURL() { return codeSourceURL; } 137 } 138 139 140 // maps package name to loaded module for modules in the boot layer 141 private static final Map<String, LoadedModule> packageToModule 142 = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER); 143 144 // maps a module name to a module reference 145 private final Map<String, ModuleReference> nameToModule; 146 147 // maps a module reference to a module reader 148 private final Map<ModuleReference, ModuleReader> moduleToReader; 149 150 // cache of resource name -> list of URLs. 151 // used only for resources that are not in module packages 152 private volatile SoftReference<Map<String, List<URL>>> resourceCache; 153 154 /** 155 * Create a new instance. 156 */ 157 BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { 158 // ensure getParent() returns null when the parent is the boot loader 159 super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); 160 161 this.parent = parent; 162 this.ucp = ucp; 163 164 this.nameToModule = new ConcurrentHashMap<>(); 165 this.moduleToReader = new ConcurrentHashMap<>(); 166 } 167 168 /** 169 * Returns {@code true} if there is a class path associated with this 170 * class loader. 171 */ 172 boolean hasClassPath() { 173 return ucp != null; 174 } 175 176 /** 177 * Register a module this class loader. This has the effect of making the 178 * types in the module visible. 179 */ 180 public void loadModule(ModuleReference mref) { 181 String mn = mref.descriptor().name(); 182 if (nameToModule.putIfAbsent(mn, mref) != null) { 183 throw new InternalError(mn + " already defined to this loader"); 184 } 185 186 LoadedModule loadedModule = new LoadedModule(this, mref); 187 for (String pn : mref.descriptor().packages()) { 188 LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); 189 if (other != null) { 190 throw new InternalError(pn + " in modules " + mn + " and " 191 + other.mref().descriptor().name()); 192 } 193 } 194 195 // clear resources cache if VM is already initialized 196 if (VM.isModuleSystemInited() && resourceCache != null) { 197 resourceCache = null; 198 } 199 } 200 201 /** 202 * Returns the {@code ModuleReference} for the named module defined to 203 * this class loader; or {@code null} if not defined. 204 * 205 * @param name The name of the module to find 206 */ 207 protected ModuleReference findModule(String name) { 208 return nameToModule.get(name); 209 } 210 211 212 // -- finding resources 213 214 /** 215 * Returns a URL to a resource of the given name in a module defined to 216 * this class loader. 217 */ 218 @Override 219 public URL findResource(String mn, String name) throws IOException { 220 URL url = null; 221 222 if (mn != null) { 223 // find in module 224 ModuleReference mref = nameToModule.get(mn); 225 if (mref != null) { 226 url = findResource(mref, name); 227 } 228 } else { 229 // find on class path 230 url = findResourceOnClassPath(name); 231 } 232 233 return checkURL(url); // check access before returning 234 } 235 236 /** 237 * Returns an input stream to a resource of the given name in a module 238 * defined to this class loader. 239 */ 240 public InputStream findResourceAsStream(String mn, String name) 241 throws IOException 242 { 243 // Need URL to resource when running with a security manager so that 244 // the right permission check is done. 245 if (System.getSecurityManager() != null || mn == null) { 246 URL url = findResource(mn, name); 247 return (url != null) ? url.openStream() : null; 248 } 249 250 // find in module defined to this loader, no security manager 251 ModuleReference mref = nameToModule.get(mn); 252 if (mref != null) { 253 return moduleReaderFor(mref).open(name).orElse(null); 254 } else { 255 return null; 256 } 257 } 258 259 /** 260 * Finds a resource with the given name in the modules defined to this 261 * class loader or its class path. 262 */ 263 @Override 264 public URL findResource(String name) { 265 String pn = Resources.toPackageName(name); 266 LoadedModule module = packageToModule.get(pn); 267 if (module != null) { 268 269 // resource is in a package of a module defined to this loader 270 if (module.loader() == this) { 271 URL url; 272 try { 273 url = findResource(module.name(), name); // checks URL 274 } catch (IOException ioe) { 275 return null; 276 } 277 if (url != null 278 && (name.endsWith(".class") 279 || url.toString().endsWith("/") 280 || isOpen(module.mref(), pn))) { 281 return url; 282 } 283 } 284 285 } else { 286 287 // not in a module package but may be in module defined to this loader 288 try { 289 List<URL> urls = findMiscResource(name); 290 if (!urls.isEmpty()) { 291 URL url = urls.get(0); 292 if (url != null) { 293 return checkURL(url); // check access before returning 294 } 295 } 296 } catch (IOException ioe) { 297 return null; 298 } 299 300 } 301 302 // search class path 303 URL url = findResourceOnClassPath(name); 304 return checkURL(url); 305 } 306 307 /** 308 * Returns an enumeration of URL objects to all the resources with the 309 * given name in modules defined to this class loader or on the class 310 * path of this loader. 311 */ 312 @Override 313 public Enumeration<URL> findResources(String name) throws IOException { 314 List<URL> checked = new ArrayList<>(); // list of checked URLs 315 316 String pn = Resources.toPackageName(name); 317 LoadedModule module = packageToModule.get(pn); 318 if (module != null) { 319 320 // resource is in a package of a module defined to this loader 321 if (module.loader() == this) { 322 URL url = findResource(module.name(), name); // checks URL 323 if (url != null 324 && (name.endsWith(".class") 325 || url.toString().endsWith("/") 326 || isOpen(module.mref(), pn))) { 327 checked.add(url); 328 } 329 } 330 331 } else { 332 // not in a package of a module defined to this loader 333 for (URL url : findMiscResource(name)) { 334 url = checkURL(url); 335 if (url != null) { 336 checked.add(url); 337 } 338 } 339 } 340 341 // class path (not checked) 342 Enumeration<URL> e = findResourcesOnClassPath(name); 343 344 // concat the checked URLs and the (not checked) class path 345 return new Enumeration<>() { 346 final Iterator<URL> iterator = checked.iterator(); 347 URL next; 348 private boolean hasNext() { 349 if (next != null) { 350 return true; 351 } else if (iterator.hasNext()) { 352 next = iterator.next(); 353 return true; 354 } else { 355 // need to check each URL 356 while (e.hasMoreElements() && next == null) { 357 next = checkURL(e.nextElement()); 358 } 359 return next != null; 360 } 361 } 362 @Override 363 public boolean hasMoreElements() { 364 return hasNext(); 365 } 366 @Override 367 public URL nextElement() { 368 if (hasNext()) { 369 URL result = next; 370 next = null; 371 return result; 372 } else { 373 throw new NoSuchElementException(); 374 } 375 } 376 }; 377 378 } 379 380 /** 381 * Returns the list of URLs to a "miscellaneous" resource in modules 382 * defined to this loader. A miscellaneous resource is not in a module 383 * package, e.g. META-INF/services/p.S. 384 * 385 * The cache used by this method avoids repeated searching of all modules. 386 */ 387 private List<URL> findMiscResource(String name) throws IOException { 388 SoftReference<Map<String, List<URL>>> ref = this.resourceCache; 389 Map<String, List<URL>> map = (ref != null) ? ref.get() : null; 390 if (map == null) { 391 map = new ConcurrentHashMap<>(); 392 this.resourceCache = new SoftReference<>(map); 393 } else { 394 List<URL> urls = map.get(name); 395 if (urls != null) 396 return urls; 397 } 398 399 // search all modules for the resource 400 List<URL> urls; 401 try { 402 urls = AccessController.doPrivileged( 403 new PrivilegedExceptionAction<>() { 404 @Override 405 public List<URL> run() throws IOException { 406 List<URL> result = null; 407 for (ModuleReference mref : nameToModule.values()) { 408 URI u = moduleReaderFor(mref).find(name).orElse(null); 409 if (u != null) { 410 try { 411 if (result == null) 412 result = new ArrayList<>(); 413 result.add(u.toURL()); 414 } catch (MalformedURLException | 415 IllegalArgumentException e) { 416 } 417 } 418 } 419 return (result != null) ? result : Collections.emptyList(); 420 } 421 }); 422 } catch (PrivilegedActionException pae) { 423 throw (IOException) pae.getCause(); 424 } 425 426 // only cache resources after VM is fully initialized 427 if (VM.isModuleSystemInited()) { 428 map.putIfAbsent(name, urls); 429 } 430 431 return urls; 432 } 433 434 /** 435 * Returns the URL to a resource in a module or {@code null} if not found. 436 */ 437 private URL findResource(ModuleReference mref, String name) throws IOException { 438 URI u; 439 if (System.getSecurityManager() == null) { 440 u = moduleReaderFor(mref).find(name).orElse(null); 441 } else { 442 try { 443 u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () { 444 @Override 445 public URI run() throws IOException { 446 return moduleReaderFor(mref).find(name).orElse(null); 447 } 448 }); 449 } catch (PrivilegedActionException pae) { 450 throw (IOException) pae.getCause(); 451 } 452 } 453 if (u != null) { 454 try { 455 return u.toURL(); 456 } catch (MalformedURLException | IllegalArgumentException e) { } 457 } 458 return null; 459 } 460 461 /** 462 * Returns the URL to a resource in a module. Returns {@code null} if not found 463 * or an I/O error occurs. 464 */ 465 private URL findResourceOrNull(ModuleReference mref, String name) { 466 try { 467 return findResource(mref, name); 468 } catch (IOException ignore) { 469 return null; 470 } 471 } 472 473 /** 474 * Returns a URL to a resource on the class path. 475 */ 476 private URL findResourceOnClassPath(String name) { 477 if (hasClassPath()) { 478 if (System.getSecurityManager() == null) { 479 return ucp.findResource(name, false); 480 } else { 481 PrivilegedAction<URL> pa = () -> ucp.findResource(name, false); 482 return AccessController.doPrivileged(pa); 483 } 484 } else { 485 // no class path 486 return null; 487 } 488 } 489 490 /** 491 * Returns the URLs of all resources of the given name on the class path. 492 */ 493 private Enumeration<URL> findResourcesOnClassPath(String name) { 494 if (hasClassPath()) { 495 if (System.getSecurityManager() == null) { 496 return ucp.findResources(name, false); 497 } else { 498 PrivilegedAction<Enumeration<URL>> pa; 499 pa = () -> ucp.findResources(name, false); 500 return AccessController.doPrivileged(pa); 501 } 502 } else { 503 // no class path 504 return Collections.emptyEnumeration(); 505 } 506 } 507 508 // -- finding/loading classes 509 510 /** 511 * Finds the class with the specified binary name. 512 */ 513 @Override 514 protected Class<?> findClass(String cn) throws ClassNotFoundException { 515 // no class loading until VM is fully initialized 516 if (!VM.isModuleSystemInited()) 517 throw new ClassNotFoundException(cn); 518 519 // find the candidate module for this class 520 LoadedModule loadedModule = findLoadedModule(cn); 521 522 Class<?> c = null; 523 if (loadedModule != null) { 524 525 // attempt to load class in module defined to this loader 526 if (loadedModule.loader() == this) { 527 c = findClassInModuleOrNull(loadedModule, cn); 528 } 529 530 } else { 531 532 // search class path 533 if (hasClassPath()) { 534 c = findClassOnClassPathOrNull(cn); 535 } 536 537 } 538 539 // not found 540 if (c == null) 541 throw new ClassNotFoundException(cn); 542 543 return c; 544 } 545 546 /** 547 * Finds the class with the specified binary name in a module. 548 * This method returns {@code null} if the class cannot be found 549 * or not defined in the specified module. 550 */ 551 @Override 552 protected Class<?> findClass(String mn, String cn) { 553 if (mn != null) { 554 // find the candidate module for this class 555 LoadedModule loadedModule = findLoadedModule(mn, cn); 556 if (loadedModule == null) { 557 return null; 558 } 559 560 // attempt to load class in module defined to this loader 561 assert loadedModule.loader() == this; 562 return findClassInModuleOrNull(loadedModule, cn); 563 } 564 565 // search class path 566 if (hasClassPath()) { 567 return findClassOnClassPathOrNull(cn); 568 } 569 570 return null; 571 } 572 573 /** 574 * Loads the class with the specified binary name. 575 */ 576 @Override 577 protected Class<?> loadClass(String cn, boolean resolve) 578 throws ClassNotFoundException 579 { 580 Class<?> c = loadClassOrNull(cn, resolve); 581 if (c == null) 582 throw new ClassNotFoundException(cn); 583 return c; 584 } 585 586 /** 587 * A variation of {@code loadCass} to load a class with the specified 588 * binary name. This method returns {@code null} when the class is not 589 * found. 590 */ 591 protected Class<?> loadClassOrNull(String cn, boolean resolve) { 592 synchronized (getClassLoadingLock(cn)) { 593 // check if already loaded 594 Class<?> c = findLoadedClass(cn); 595 596 if (c == null) { 597 598 // find the candidate module for this class 599 LoadedModule loadedModule = findLoadedModule(cn); 600 if (loadedModule != null) { 601 602 // package is in a module 603 BuiltinClassLoader loader = loadedModule.loader(); 604 if (loader == this) { 605 if (VM.isModuleSystemInited()) { 606 c = findClassInModuleOrNull(loadedModule, cn); 607 } 608 } else { 609 // delegate to the other loader 610 c = loader.loadClassOrNull(cn); 611 } 612 613 } else { 614 615 // check parent 616 if (parent != null) { 617 c = parent.loadClassOrNull(cn); 618 } 619 620 // check class path 621 if (c == null && hasClassPath() && VM.isModuleSystemInited()) { 622 c = findClassOnClassPathOrNull(cn); 623 } 624 } 625 626 } 627 628 if (resolve && c != null) 629 resolveClass(c); 630 631 return c; 632 } 633 } 634 635 /** 636 * A variation of {@code loadCass} to load a class with the specified 637 * binary name. This method returns {@code null} when the class is not 638 * found. 639 */ 640 protected Class<?> loadClassOrNull(String cn) { 641 return loadClassOrNull(cn, false); 642 } 643 644 /** 645 * Find the candidate loaded module for the given class name. 646 * Returns {@code null} if none of the modules defined to this 647 * class loader contain the API package for the class. 648 */ 649 private LoadedModule findLoadedModule(String cn) { 650 int pos = cn.lastIndexOf('.'); 651 if (pos < 0) 652 return null; // unnamed package 653 654 String pn = cn.substring(0, pos); 655 return packageToModule.get(pn); 656 } 657 658 /** 659 * Find the candidate loaded module for the given class name 660 * in the named module. Returns {@code null} if the named module 661 * is not defined to this class loader or does not contain 662 * the API package for the class. 663 */ 664 private LoadedModule findLoadedModule(String mn, String cn) { 665 LoadedModule loadedModule = findLoadedModule(cn); 666 if (loadedModule != null && mn.equals(loadedModule.name())) { 667 return loadedModule; 668 } else { 669 return null; 670 } 671 } 672 673 /** 674 * Finds the class with the specified binary name if in a module 675 * defined to this ClassLoader. 676 * 677 * @return the resulting Class or {@code null} if not found 678 */ 679 private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) { 680 if (System.getSecurityManager() == null) { 681 return defineClass(cn, loadedModule); 682 } else { 683 PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule); 684 return AccessController.doPrivileged(pa); 685 } 686 } 687 688 /** 689 * Finds the class with the specified binary name on the class path. 690 * 691 * @return the resulting Class or {@code null} if not found 692 */ 693 private Class<?> findClassOnClassPathOrNull(String cn) { 694 String path = cn.replace('.', '/').concat(".class"); 695 if (System.getSecurityManager() == null) { 696 Resource res = ucp.getResource(path, false); 697 if (res != null) { 698 try { 699 return defineClass(cn, res); 700 } catch (IOException ioe) { 701 // TBD on how I/O errors should be propagated 702 } 703 } 704 return null; 705 } else { 706 // avoid use of lambda here 707 PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() { 708 public Class<?> run() { 709 Resource res = ucp.getResource(path, false); 710 if (res != null) { 711 try { 712 return defineClass(cn, res); 713 } catch (IOException ioe) { 714 // TBD on how I/O errors should be propagated 715 } 716 } 717 return null; 718 } 719 }; 720 return AccessController.doPrivileged(pa); 721 } 722 } 723 724 /** 725 * Defines the given binary class name to the VM, loading the class 726 * bytes from the given module. 727 * 728 * @return the resulting Class or {@code null} if an I/O error occurs 729 */ 730 private Class<?> defineClass(String cn, LoadedModule loadedModule) { 731 ModuleReference mref = loadedModule.mref(); 732 ModuleReader reader = moduleReaderFor(mref); 733 734 try { 735 ByteBuffer bb = null; 736 URL csURL = null; 737 738 // locate class file, special handling for patched modules to 739 // avoid locating the resource twice 740 String rn = cn.replace('.', '/').concat(".class"); 741 if (reader instanceof PatchedModuleReader) { 742 Resource r = ((PatchedModuleReader)reader).findResource(rn); 743 if (r != null) { 744 bb = r.getByteBuffer(); 745 csURL = r.getCodeSourceURL(); 746 } 747 } else { 748 bb = reader.read(rn).orElse(null); 749 csURL = loadedModule.codeSourceURL(); 750 } 751 752 if (bb == null) { 753 // class not found 754 return null; 755 } 756 757 CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); 758 try { 759 // define class to VM 760 return defineClass(cn, bb, cs); 761 762 } finally { 763 reader.release(bb); 764 } 765 766 } catch (IOException ioe) { 767 // TBD on how I/O errors should be propagated 768 return null; 769 } 770 } 771 772 /** 773 * Defines the given binary class name to the VM, loading the class 774 * bytes via the given Resource object. 775 * 776 * @return the resulting Class 777 * @throws IOException if reading the resource fails 778 * @throws SecurityException if there is a sealing violation (JAR spec) 779 */ 780 private Class<?> defineClass(String cn, Resource res) throws IOException { 781 URL url = res.getCodeSourceURL(); 782 783 // if class is in a named package then ensure that the package is defined 784 int pos = cn.lastIndexOf('.'); 785 if (pos != -1) { 786 String pn = cn.substring(0, pos); 787 Manifest man = res.getManifest(); 788 defineOrCheckPackage(pn, man, url); 789 } 790 791 // defines the class to the runtime 792 ByteBuffer bb = res.getByteBuffer(); 793 if (bb != null) { 794 CodeSigner[] signers = res.getCodeSigners(); 795 CodeSource cs = new CodeSource(url, signers); 796 return defineClass(cn, bb, cs); 797 } else { 798 byte[] b = res.getBytes(); 799 CodeSigner[] signers = res.getCodeSigners(); 800 CodeSource cs = new CodeSource(url, signers); 801 return defineClass(cn, b, 0, b.length, cs); 802 } 803 } 804 805 806 // -- packages 807 808 /** 809 * Defines a package in this ClassLoader. If the package is already defined 810 * then its sealing needs to be checked if sealed by the legacy sealing 811 * mechanism. 812 * 813 * @throws SecurityException if there is a sealing violation (JAR spec) 814 */ 815 protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { 816 Package pkg = getAndVerifyPackage(pn, man, url); 817 if (pkg == null) { 818 try { 819 if (man != null) { 820 pkg = definePackage(pn, man, url); 821 } else { 822 pkg = definePackage(pn, null, null, null, null, null, null, null); 823 } 824 } catch (IllegalArgumentException iae) { 825 // defined by another thread so need to re-verify 826 pkg = getAndVerifyPackage(pn, man, url); 827 if (pkg == null) 828 throw new InternalError("Cannot find package: " + pn); 829 } 830 } 831 return pkg; 832 } 833 834 /** 835 * Get the Package with the specified package name. If defined 836 * then verify that it against the manifest and code source. 837 * 838 * @throws SecurityException if there is a sealing violation (JAR spec) 839 */ 840 private Package getAndVerifyPackage(String pn, Manifest man, URL url) { 841 Package pkg = getDefinedPackage(pn); 842 if (pkg != null) { 843 if (pkg.isSealed()) { 844 if (!pkg.isSealed(url)) { 845 throw new SecurityException( 846 "sealing violation: package " + pn + " is sealed"); 847 } 848 } else { 849 // can't seal package if already defined without sealing 850 if ((man != null) && isSealed(pn, man)) { 851 throw new SecurityException( 852 "sealing violation: can't seal package " + pn + 853 ": already defined"); 854 } 855 } 856 } 857 return pkg; 858 } 859 860 /** 861 * Defines a new package in this ClassLoader. The attributes in the specified 862 * Manifest are use to get the package version and sealing information. 863 * 864 * @throws IllegalArgumentException if the package name duplicates an 865 * existing package either in this class loader or one of its ancestors 866 */ 867 private Package definePackage(String pn, Manifest man, URL url) { 868 String specTitle = null; 869 String specVersion = null; 870 String specVendor = null; 871 String implTitle = null; 872 String implVersion = null; 873 String implVendor = null; 874 String sealed = null; 875 URL sealBase = null; 876 877 if (man != null) { 878 Attributes attr = man.getAttributes(pn.replace('.', '/').concat("/")); 879 if (attr != null) { 880 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 881 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 882 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 883 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 884 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 885 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 886 sealed = attr.getValue(Attributes.Name.SEALED); 887 } 888 889 attr = man.getMainAttributes(); 890 if (attr != null) { 891 if (specTitle == null) 892 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 893 if (specVersion == null) 894 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 895 if (specVendor == null) 896 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 897 if (implTitle == null) 898 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 899 if (implVersion == null) 900 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 901 if (implVendor == null) 902 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 903 if (sealed == null) 904 sealed = attr.getValue(Attributes.Name.SEALED); 905 } 906 907 // package is sealed 908 if ("true".equalsIgnoreCase(sealed)) 909 sealBase = url; 910 } 911 return definePackage(pn, 912 specTitle, 913 specVersion, 914 specVendor, 915 implTitle, 916 implVersion, 917 implVendor, 918 sealBase); 919 } 920 921 /** 922 * Returns {@code true} if the specified package name is sealed according to 923 * the given manifest. 924 */ 925 private boolean isSealed(String pn, Manifest man) { 926 String path = pn.replace('.', '/').concat("/"); 927 Attributes attr = man.getAttributes(path); 928 String sealed = null; 929 if (attr != null) 930 sealed = attr.getValue(Attributes.Name.SEALED); 931 if (sealed == null && (attr = man.getMainAttributes()) != null) 932 sealed = attr.getValue(Attributes.Name.SEALED); 933 return "true".equalsIgnoreCase(sealed); 934 } 935 936 // -- permissions 937 938 /** 939 * Returns the permissions for the given CodeSource. 940 */ 941 @Override 942 protected PermissionCollection getPermissions(CodeSource cs) { 943 PermissionCollection perms = super.getPermissions(cs); 944 945 // add the permission to access the resource 946 URL url = cs.getLocation(); 947 if (url == null) 948 return perms; 949 Permission p = null; 950 try { 951 p = url.openConnection().getPermission(); 952 if (p != null) { 953 // for directories then need recursive access 954 if (p instanceof FilePermission) { 955 String path = p.getName(); 956 if (path.endsWith(File.separator)) { 957 path += "-"; 958 p = new FilePermission(path, "read"); 959 } 960 } 961 perms.add(p); 962 } 963 } catch (IOException ioe) { } 964 965 return perms; 966 } 967 968 969 // -- miscellaneous supporting methods 970 971 /** 972 * Returns the ModuleReader for the given module. 973 */ 974 private ModuleReader moduleReaderFor(ModuleReference mref) { 975 return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader); 976 } 977 978 /** 979 * Creates a ModuleReader for the given module. 980 */ 981 private static ModuleReader createModuleReader(ModuleReference mref) { 982 try { 983 return mref.open(); 984 } catch (IOException e) { 985 // Return a null module reader to avoid a future class load 986 // attempting to open the module again. 987 return new NullModuleReader(); 988 } 989 } 990 991 /** 992 * A ModuleReader that doesn't read any resources. 993 */ 994 private static class NullModuleReader implements ModuleReader { 995 @Override 996 public Optional<URI> find(String name) { 997 return Optional.empty(); 998 } 999 @Override 1000 public Stream<String> list() { 1001 return Stream.empty(); 1002 } 1003 @Override 1004 public void close() { 1005 throw new InternalError("Should not get here"); 1006 } 1007 }; 1008 1009 /** 1010 * Returns true if the given module opens the given package 1011 * unconditionally. 1012 * 1013 * @implNote This method currently iterates over each of the open 1014 * packages. This will be replaced once the ModuleDescriptor.Opens 1015 * API is updated. 1016 */ 1017 private boolean isOpen(ModuleReference mref, String pn) { 1018 ModuleDescriptor descriptor = mref.descriptor(); 1019 if (descriptor.isOpen() || descriptor.isAutomatic()) 1020 return true; 1021 for (ModuleDescriptor.Opens opens : descriptor.opens()) { 1022 String source = opens.source(); 1023 if (!opens.isQualified() && source.equals(pn)) { 1024 return true; 1025 } 1026 } 1027 return false; 1028 } 1029 1030 /** 1031 * Checks access to the given URL. We use URLClassPath for consistent 1032 * checking with java.net.URLClassLoader. 1033 */ 1034 private static URL checkURL(URL url) { 1035 return URLClassPath.checkURL(url); 1036 } 1037} 1038