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