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