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