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