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