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