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