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