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); // checks URL 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> checked = new ArrayList<>(); // list of checked 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); // checks URL 367 if (url != null 368 && (name.endsWith(".class") 369 || url.toString().endsWith("/") 370 || isOpen(module.mref(), pn))) { 371 checked.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 checked.add(url); 380 } 381 } 382 } 383 384 // class path (not checked) 385 Enumeration<URL> e = findResourcesOnClassPath(name); 386 387 // concat the checked URLs and the (not checked) class path 388 return new Enumeration<>() { 389 final Iterator<URL> iterator = checked.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 // need to check each URL 399 while (e.hasMoreElements() && next == null) { 400 next = e.nextElement(); 401 } 402 return next != null; 403 } 404 } 405 @Override 406 public boolean hasMoreElements() { 407 return hasNext(); 408 } 409 @Override 410 public URL nextElement() { 411 if (hasNext()) { 412 URL result = next; 413 next = null; 414 return result; 415 } else { 416 throw new NoSuchElementException(); 417 } 418 } 419 }; 420 421 } 422 423 /** 424 * Returns the list of URLs to a "miscellaneous" resource in modules 425 * defined to this loader. A miscellaneous resource is not in a module 426 * package, e.g. META-INF/services/p.S. 427 * 428 * The cache used by this method avoids repeated searching of all modules. 429 */ 430 private List<URL> findMiscResource(String name) throws IOException { 431 SoftReference<Map<String, List<URL>>> ref = this.resourceCache; 432 Map<String, List<URL>> map = (ref != null) ? ref.get() : null; 433 if (map == null) { 434 // only cache resources after VM is fully initialized 435 if (VM.isModuleSystemInited()) { 436 map = new ConcurrentHashMap<>(); 437 this.resourceCache = new SoftReference<>(map); 438 } 439 } else { 440 List<URL> urls = map.get(name); 441 if (urls != null) 442 return urls; 443 } 444 445 // search all modules for the resource 446 List<URL> urls = null; 447 for (ModuleReference mref : nameToModule.values()) { 448 URI u = moduleReaderFor(mref).find(name).orElse(null); 449 if (u != null) { 450 try { 451 if (urls == null) 452 urls = new ArrayList<>(); 453 urls.add(u.toURL()); 454 } catch (MalformedURLException | IllegalArgumentException e) { 455 } 456 } 457 } 458 if (urls == null) { 459 urls = List.of(); 460 } 461 462 // only cache resources after VM is fully initialized 463 if (map != null) { 464 map.putIfAbsent(name, urls); 465 } 466 467 return urls; 468 } 469 470 /** 471 * Returns the URL to a resource in a module or {@code null} if not found. 472 */ 473 private URL findResource(ModuleReference mref, String name) throws IOException { 474 URI u = moduleReaderFor(mref).find(name).orElse(null); 475 if (u != null) { 476 try { 477 return u.toURL(); 478 } catch (MalformedURLException | IllegalArgumentException e) { } 479 } 480 return null; 481 } 482 483 /** 484 * Returns a URL to a resource on the class path. 485 */ 486 private URL findResourceOnClassPath(String name) { 487 if (hasClassPath()) { 488 return ucp.findResource(name, false); 489 } else { 490 // no class path 491 return null; 492 } 493 } 494 495 /** 496 * Returns the URLs of all resources of the given name on the class path. 497 */ 498 private Enumeration<URL> findResourcesOnClassPath(String name) { 499 if (hasClassPath()) { 500 return ucp.findResources(name, false); 501 } else { 502 // no class path 503 return Collections.emptyEnumeration(); 504 } 505 } 506 507 // -- finding/loading classes 508 509 /** 510 * Finds the class with the specified binary name. 511 */ 512 @Override 513 protected Class<?> findClass(String cn) throws ClassNotFoundException { 514 // no class loading until VM is fully initialized 515 if (!VM.isModuleSystemInited()) 516 throw new ClassNotFoundException(cn); 517 518 // find the candidate module for this class 519 LoadedModule loadedModule = findLoadedModule(cn); 520 521 Class<?> c = null; 522 if (loadedModule != null) { 523 524 // attempt to load class in module defined to this loader 525 if (loadedModule.loader() == this) { 526 c = findClassInModuleOrNull(loadedModule, cn); 527 } 528 529 } else { 530 531 // search class path 532 if (hasClassPath()) { 533 c = findClassOnClassPathOrNull(cn); 534 } 535 536 } 537 538 // not found 539 if (c == null) 540 throw new ClassNotFoundException(cn); 541 542 return c; 543 } 544 545 /** 546 * Finds the class with the specified binary name in a module. 547 * This method returns {@code null} if the class cannot be found 548 * or not defined in the specified module. 549 */ 550 @Override 551 protected Class<?> findClass(String mn, String cn) { 552 if (mn != null) { 553 // find the candidate module for this class 554 LoadedModule loadedModule = findLoadedModule(mn, cn); 555 if (loadedModule == null) { 556 return null; 557 } 558 559 // attempt to load class in module defined to this loader 560 assert loadedModule.loader() == this; 561 return findClassInModuleOrNull(loadedModule, cn); 562 } 563 564 // search class path 565 if (hasClassPath()) { 566 return findClassOnClassPathOrNull(cn); 567 } 568 569 return null; 570 } 571 572 /** 573 * Loads the class with the specified binary name. 574 */ 575 @Override 576 protected Class<?> loadClass(String cn, boolean resolve) 577 throws ClassNotFoundException 578 { 579 Class<?> c = loadClassOrNull(cn, resolve); 580 if (c == null) 581 throw new ClassNotFoundException(cn); 582 return c; 583 } 584 585 /** 586 * A variation of {@code loadClass} to load a class with the specified 587 * binary name. This method returns {@code null} when the class is not 588 * found. 589 */ 590 protected Class<?> loadClassOrNull(String cn, boolean resolve) { 591 synchronized (getClassLoadingLock(cn)) { 592 // check if already loaded 593 Class<?> c = findLoadedClass(cn); 594 595 if (c == null) { 596 597 // find the candidate module for this class 598 LoadedModule loadedModule = findLoadedModule(cn); 599 if (loadedModule != null) { 600 601 // package is in a module 602 BuiltinClassLoader loader = loadedModule.loader(); 603 if (loader == this) { 604 if (VM.isModuleSystemInited()) { 605 c = findClassInModuleOrNull(loadedModule, cn); 606 } 607 } else { 608 // delegate to the other loader 609 c = loader.loadClassOrNull(cn); 610 } 611 612 } else { 613 614 // check parent 615 if (parent != null) { 616 c = parent.loadClassOrNull(cn); 617 } 618 619 // check class path 620 if (c == null && hasClassPath() && VM.isModuleSystemInited()) { 621 c = findClassOnClassPathOrNull(cn); 622 } 623 } 624 625 } 626 627 if (resolve && c != null) 628 resolveClass(c); 629 630 return c; 631 } 632 } 633 634 /** 635 * A variation of {@code loadClass} to load a class with the specified 636 * binary name. This method returns {@code null} when the class is not 637 * found. 638 */ 639 protected final Class<?> loadClassOrNull(String cn) { 640 return loadClassOrNull(cn, false); 641 } 642 643 /** 644 * Finds the candidate loaded module for the given class name. 645 * Returns {@code null} if none of the modules defined to this 646 * class loader contain the API package for the class. 647 */ 648 private LoadedModule findLoadedModule(String cn) { 649 int pos = cn.lastIndexOf('.'); 650 if (pos < 0) 651 return null; // unnamed package 652 653 String pn = cn.substring(0, pos); 654 return packageToModule.get(pn); 655 } 656 657 /** 658 * Finds the candidate loaded module for the given class name 659 * in the named module. Returns {@code null} if the named module 660 * is not defined to this class loader or does not contain 661 * the API package for the class. 662 */ 663 private LoadedModule findLoadedModule(String mn, String cn) { 664 LoadedModule loadedModule = findLoadedModule(cn); 665 if (loadedModule != null && mn.equals(loadedModule.name())) { 666 return loadedModule; 667 } else { 668 return null; 669 } 670 } 671 672 /** 673 * Finds the class with the specified binary name if in a module 674 * defined to this ClassLoader. 675 * 676 * @return the resulting Class or {@code null} if not found 677 */ 678 private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) { 679 return defineClass(cn, loadedModule); 680 } 681 682 /** 683 * Finds the class with the specified binary name on the class path. 684 * 685 * @return the resulting Class or {@code null} if not found 686 */ 687 private Class<?> findClassOnClassPathOrNull(String cn) { 688 String path = cn.replace('.', '/').concat(".class"); 689 Resource res = ucp.getResource(path, false); 690 if (res != null) { 691 try { 692 return defineClass(cn, res); 693 } catch (IOException ioe) { 694 // TBD on how I/O errors should be propagated 695 } 696 } 697 return null; 698 } 699 700 /** 701 * Defines the given binary class name to the VM, loading the class 702 * bytes from the given module. 703 * 704 * @return the resulting Class or {@code null} if an I/O error occurs 705 */ 706 private Class<?> defineClass(String cn, LoadedModule loadedModule) { 707 ModuleReference mref = loadedModule.mref(); 708 ModuleReader reader = moduleReaderFor(mref); 709 710 try { 711 ByteBuffer bb = null; 712 URL csURL = null; 713 714 // locate class file, special handling for patched modules to 715 // avoid locating the resource twice 716 String rn = cn.replace('.', '/').concat(".class"); 717 if (reader instanceof PatchedModuleReader) { 718 Resource r = ((PatchedModuleReader)reader).findResource(rn); 719 if (r != null) { 720 bb = r.getByteBuffer(); 721 csURL = r.getCodeSourceURL(); 722 } 723 } else { 724 bb = reader.read(rn).orElse(null); 725 csURL = loadedModule.codeSourceURL(); 726 } 727 728 if (bb == null) { 729 // class not found 730 return null; 731 } 732 733 CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); 734 try { 735 // define class to VM 736 return defineClass(cn, bb, cs); 737 738 } finally { 739 reader.release(bb); 740 } 741 742 } catch (IOException ioe) { 743 // TBD on how I/O errors should be propagated 744 return null; 745 } 746 } 747 748 /** 749 * Defines the given binary class name to the VM, loading the class 750 * bytes via the given Resource object. 751 * 752 * @return the resulting Class 753 * @throws IOException if reading the resource fails 754 * @throws SecurityException if there is a sealing violation (JAR spec) 755 */ 756 private Class<?> defineClass(String cn, Resource res) throws IOException { 757 URL url = res.getCodeSourceURL(); 758 759 // if class is in a named package then ensure that the package is defined 760 int pos = cn.lastIndexOf('.'); 761 if (pos != -1) { 762 String pn = cn.substring(0, pos); 763 Manifest man = res.getManifest(); 764 defineOrCheckPackage(pn, man, url); 765 } 766 767 // defines the class to the runtime 768 ByteBuffer bb = res.getByteBuffer(); 769 if (bb != null) { 770 CodeSigner[] signers = res.getCodeSigners(); 771 CodeSource cs = new CodeSource(url, signers); 772 return defineClass(cn, bb, cs); 773 } else { 774 byte[] b = res.getBytes(); 775 CodeSigner[] signers = res.getCodeSigners(); 776 CodeSource cs = new CodeSource(url, signers); 777 return defineClass(cn, b, 0, b.length, cs); 778 } 779 } 780 781 782 // -- packages 783 784 /** 785 * Defines a package in this ClassLoader. If the package is already defined 786 * then its sealing needs to be checked if sealed by the legacy sealing 787 * mechanism. 788 * 789 * @throws SecurityException if there is a sealing violation (JAR spec) 790 */ 791 protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { 792 Package pkg = getAndVerifyPackage(pn, man, url); 793 if (pkg == null) { 794 try { 795 if (man != null) { 796 pkg = definePackage(pn, man, url); 797 } else { 798 pkg = definePackage(pn, null, null, null, null, null, null, null); 799 } 800 } catch (IllegalArgumentException iae) { 801 // defined by another thread so need to re-verify 802 pkg = getAndVerifyPackage(pn, man, url); 803 if (pkg == null) 804 throw new InternalError("Cannot find package: " + pn); 805 } 806 } 807 return pkg; 808 } 809 810 /** 811 * Gets the Package with the specified package name. If defined 812 * then verifies it against the manifest and code source. 813 * 814 * @throws SecurityException if there is a sealing violation (JAR spec) 815 */ 816 private Package getAndVerifyPackage(String pn, Manifest man, URL url) { 817 Package pkg = getDefinedPackage(pn); 818 if (pkg != null) { 819 if (pkg.isSealed()) { 820 if (!pkg.isSealed(url)) { 821 throw new SecurityException( 822 "sealing violation: package " + pn + " is sealed"); 823 } 824 } else { 825 // can't seal package if already defined without sealing 826 if ((man != null) && isSealed(pn, man)) { 827 throw new SecurityException( 828 "sealing violation: can't seal package " + pn + 829 ": already defined"); 830 } 831 } 832 } 833 return pkg; 834 } 835 836 /** 837 * Defines a new package in this ClassLoader. The attributes in the specified 838 * Manifest are used to get the package version and sealing information. 839 * 840 * @throws IllegalArgumentException if the package name duplicates an 841 * existing package either in this class loader or one of its ancestors 842 * @throws SecurityException if the package name is untrusted in the manifest 843 */ 844 private Package definePackage(String pn, Manifest man, URL url) { 845 String specTitle = null; 846 String specVersion = null; 847 String specVendor = null; 848 String implTitle = null; 849 String implVersion = null; 850 String implVendor = null; 851 String sealed = null; 852 URL sealBase = null; 853 854 if (man != null) { 855 Attributes attr = SharedSecrets.javaUtilJarAccess() 856 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 857 if (attr != null) { 858 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 859 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 860 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 861 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 862 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 863 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 864 sealed = attr.getValue(Attributes.Name.SEALED); 865 } 866 867 attr = man.getMainAttributes(); 868 if (attr != null) { 869 if (specTitle == null) 870 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 871 if (specVersion == null) 872 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 873 if (specVendor == null) 874 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 875 if (implTitle == null) 876 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 877 if (implVersion == null) 878 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 879 if (implVendor == null) 880 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 881 if (sealed == null) 882 sealed = attr.getValue(Attributes.Name.SEALED); 883 } 884 885 // package is sealed 886 if ("true".equalsIgnoreCase(sealed)) 887 sealBase = url; 888 } 889 return definePackage(pn, 890 specTitle, 891 specVersion, 892 specVendor, 893 implTitle, 894 implVersion, 895 implVendor, 896 sealBase); 897 } 898 899 /** 900 * Returns {@code true} if the specified package name is sealed according to 901 * the given manifest. 902 * 903 * @throws SecurityException if the package name is untrusted in the manifest 904 */ 905 private boolean isSealed(String pn, Manifest man) { 906 Attributes attr = SharedSecrets.javaUtilJarAccess() 907 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 908 String sealed = null; 909 if (attr != null) 910 sealed = attr.getValue(Attributes.Name.SEALED); 911 if (sealed == null && (attr = man.getMainAttributes()) != null) 912 sealed = attr.getValue(Attributes.Name.SEALED); 913 return "true".equalsIgnoreCase(sealed); 914 } 915 916 // -- miscellaneous supporting methods 917 918 /** 919 * Returns the ModuleReader for the given module, creating it if needed. 920 */ 921 private ModuleReader moduleReaderFor(ModuleReference mref) { 922 ModuleReader reader = moduleToReader.get(mref); 923 if (reader == null) { 924 // avoid method reference during startup 925 Function<ModuleReference, ModuleReader> create = new Function<>() { 926 public ModuleReader apply(ModuleReference moduleReference) { 927 try { 928 return mref.open(); 929 } catch (IOException e) { 930 // Return a null module reader to avoid a future class 931 // load attempting to open the module again. 932 return new NullModuleReader(); 933 } 934 } 935 }; 936 reader = moduleToReader.computeIfAbsent(mref, create); 937 } 938 return reader; 939 } 940 941 /** 942 * A ModuleReader that doesn't read any resources. 943 */ 944 private static class NullModuleReader implements ModuleReader { 945 @Override 946 public Optional<URI> find(String name) { 947 return Optional.empty(); 948 } 949 @Override 950 public Stream<String> list() { 951 return Stream.empty(); 952 } 953 @Override 954 public void close() { 955 throw new InternalError("Should not get here"); 956 } 957 }; 958 959 /** 960 * Returns true if the given module opens the given package 961 * unconditionally. 962 * 963 * @implNote This method currently iterates over each of the open 964 * packages. This will be replaced once the ModuleDescriptor.Opens 965 * API is updated. 966 */ 967 private boolean isOpen(ModuleReference mref, String pn) { 968 ModuleDescriptor descriptor = mref.descriptor(); 969 if (descriptor.isOpen() || descriptor.isAutomatic()) 970 return true; 971 for (ModuleDescriptor.Opens opens : descriptor.opens()) { 972 String source = opens.source(); 973 if (!opens.isQualified() && source.equals(pn)) { 974 return true; 975 } 976 } 977 return false; 978 } 979 980 // Called from VM only, during -Xshare:dump 981 private void resetArchivedStates() { 982 ucp = null; 983 resourceCache = null; 984 if (!moduleToReader.isEmpty()) { 985 moduleToReader.clear(); 986 } 987 } 988 }