1 /* 2 * Copyright (c) 2014, 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 java.lang.reflect; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.lang.module.Configuration; 31 import java.lang.module.ModuleReference; 32 import java.lang.module.ModuleDescriptor; 33 import java.lang.module.ModuleDescriptor.Exports; 34 import java.lang.module.ModuleDescriptor.Provides; 35 import java.lang.module.ModuleDescriptor.Version; 36 import java.lang.module.ResolvedModule; 37 import java.net.URI; 38 import java.net.URL; 39 import java.util.Collections; 40 import java.util.HashMap; 41 import java.util.HashSet; 42 import java.util.Map; 43 import java.util.Objects; 44 import java.util.Optional; 45 import java.util.Set; 46 import java.util.function.Function; 47 import java.util.stream.Stream; 48 49 import jdk.internal.loader.BuiltinClassLoader; 50 import jdk.internal.loader.BootLoader; 51 import jdk.internal.misc.JavaLangReflectModuleAccess; 52 import jdk.internal.misc.SharedSecrets; 53 import jdk.internal.module.ServicesCatalog; 54 import sun.reflect.CallerSensitive; 55 import sun.reflect.Reflection; 56 import sun.security.util.SecurityConstants; 57 58 /** 59 * Represents a run-time module, either {@link #isNamed() named} or unnamed. 60 * 61 * <p> Named modules have a {@link #getName() name} and are constructed by the 62 * Java Virtual Machine when a graph of modules is defined to the Java virtual 63 * machine to create a module {@link Layer Layer}. </p> 64 * 65 * <p> An unnamed module does not have a name. There is an unnamed module 66 * per {@link ClassLoader ClassLoader} that is obtained by invoking the class 67 * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The 68 * {@link Class#getModule() getModule} method of all types defined by a class 69 * loader that are not in a named module return the class loader's unnamed 70 * module. </p> 71 * 72 * <p> The package names that are parameters or returned by methods defined in 73 * this class are the fully-qualified names of the packages as defined in 74 * section 6.5.3 of <cite>The Java™ Language Specification </cite>, for 75 * example, {@code "java.lang"}. </p> 76 * 77 * <p> Unless otherwise specified, passing a {@code null} argument to a method 78 * in this class causes a {@link NullPointerException NullPointerException} to 79 * be thrown. </p> 80 * 81 * @since 9 82 * @see java.lang.Class#getModule 83 */ 84 85 public final class Module { 86 87 // the layer that contains this module, can be null 88 private final Layer layer; 89 90 // module name and loader, these fields are read by VM 91 private final String name; 92 private final ClassLoader loader; 93 94 // the module descriptor 95 private final ModuleDescriptor descriptor; 96 97 98 /** 99 * Creates a new named Module. The resulting Module will be defined to the 100 * VM but will not read any other modules, will not have any exports setup 101 * and will not be registered in the service catalog. 102 */ 103 private Module(Layer layer, 104 ClassLoader loader, 105 ModuleDescriptor descriptor, 106 URI uri) 107 { 108 this.layer = layer; 109 this.name = descriptor.name(); 110 this.loader = loader; 111 this.descriptor = descriptor; 112 113 // define module to VM 114 115 Set<String> packages = descriptor.packages(); 116 int n = packages.size(); 117 String[] array = new String[n]; 118 int i = 0; 119 for (String pn : packages) { 120 array[i++] = pn.replace('.', '/'); 121 } 122 Version version = descriptor.version().orElse(null); 123 String vs = Objects.toString(version, null); 124 String loc = Objects.toString(uri, null); 125 126 defineModule0(this, vs, loc, array); 127 } 128 129 130 /** 131 * Create the unnamed Module for the given ClassLoader. 132 * 133 * @see ClassLoader#getUnnamedModule 134 */ 135 private Module(ClassLoader loader) { 136 this.layer = null; 137 this.name = null; 138 this.loader = loader; 139 this.descriptor = null; 140 141 // unnamed modules are loose 142 this.loose = true; 143 } 144 145 146 /** 147 * Creates a named module but without defining the module to the VM. 148 * 149 * @apiNote This constructor is for VM white-box testing. 150 */ 151 Module(ClassLoader loader, ModuleDescriptor descriptor) { 152 this.layer = null; 153 this.name = descriptor.name(); 154 this.loader = loader; 155 this.descriptor = descriptor; 156 } 157 158 159 160 /** 161 * Returns {@code true} if this module is a named module. 162 * 163 * @return {@code true} if this is a named module 164 * 165 * @see ClassLoader#getUnnamedModule() 166 */ 167 public boolean isNamed() { 168 return name != null; 169 } 170 171 /** 172 * Returns the module name or {@code null} if this module is an unnamed 173 * module. 174 * 175 * @return The module name 176 */ 177 public String getName() { 178 return name; 179 } 180 181 /** 182 * Returns the {@code ClassLoader} for this module. 183 * 184 * <p> If there is a security manager then its {@code checkPermission} 185 * method if first called with a {@code RuntimePermission("getClassLoader")} 186 * permission to check that the caller is allowed to get access to the 187 * class loader. </p> 188 * 189 * @return The class loader for this module 190 * 191 * @throws SecurityException 192 * If denied by the security manager 193 */ 194 public ClassLoader getClassLoader() { 195 SecurityManager sm = System.getSecurityManager(); 196 if (sm != null) { 197 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); 198 } 199 return loader; 200 } 201 202 /** 203 * Returns the module descriptor for this module or {@code null} if this 204 * module is an unnamed module. 205 * 206 * @return The module descriptor for this module 207 */ 208 public ModuleDescriptor getDescriptor() { 209 return descriptor; 210 } 211 212 /** 213 * Returns the layer that contains this module or {@code null} if this 214 * module is not in a layer. 215 * 216 * A module {@code Layer} contains named modules and therefore this 217 * method always returns {@code null} when invoked on an unnamed module. 218 * 219 * <p> <a href="Proxy.html#dynamicmodule">Dynamic modules</a> are named 220 * modules that are generated at runtime. A dynamic module may or may 221 * not be in a module Layer. </p> 222 * 223 * @return The layer that contains this module 224 * 225 * @see Proxy 226 */ 227 public Layer getLayer() { 228 if (isNamed()) { 229 Layer layer = this.layer; 230 if (layer != null) 231 return layer; 232 233 // special-case java.base as it is created before the boot Layer 234 if (loader == null && name.equals("java.base")) { 235 return SharedSecrets.getJavaLangAccess().getBootLayer(); 236 } 237 } 238 239 return null; 240 } 241 242 243 // -- readability -- 244 245 // true if this module reads all unnamed modules (a.k.a. loose module) 246 private volatile boolean loose; 247 248 // the modules that this module permanently reads 249 // (will be final when the modules are defined in reverse topology order) 250 private volatile Set<Module> reads; 251 252 // additional module (2nd key) that some module (1st key) reflectively reads 253 private static final WeakPairMap<Module, Module, Boolean> transientReads 254 = new WeakPairMap<>(); 255 256 257 /** 258 * Indicates if this module reads the given module. This method returns 259 * {@code true} if invoked to test if this module reads itself. It also 260 * returns {@code true} if invoked on an unnamed module (as unnamed 261 * modules read all modules). 262 * 263 * @param other 264 * The other module 265 * 266 * @return {@code true} if this module reads {@code other} 267 * 268 * @see #addReads(Module) 269 */ 270 public boolean canRead(Module other) { 271 Objects.requireNonNull(other); 272 273 // an unnamed module reads all modules 274 if (!this.isNamed()) 275 return true; 276 277 // all modules read themselves 278 if (other == this) 279 return true; 280 281 // check if this module reads other 282 if (other.isNamed()) { 283 284 Set<Module> reads = this.reads; // volatile read 285 if (reads != null && reads.contains(other)) 286 return true; 287 288 } else { 289 290 // loose modules read all unnamed modules 291 if (this.loose) 292 return true; 293 294 } 295 296 // check if this module reads the other module reflectively 297 return transientReads.constainsKeyPair(this, other); 298 } 299 300 /** 301 * If the caller's module is this module then update this module to read 302 * the given module. 303 * 304 * This method is a no-op if {@code other} is this module (all modules can 305 * read themselves) or this module is an unnamed module (as unnamed modules 306 * read all modules). 307 * 308 * @param other 309 * The other module 310 * 311 * @return this module 312 * 313 * @throws IllegalStateException 314 * If this is a named module and the caller is not this module 315 * 316 * @see #canRead 317 */ 318 @CallerSensitive 319 public Module addReads(Module other) { 320 Objects.requireNonNull(other); 321 if (this.isNamed()) { 322 Module caller = Reflection.getCallerClass().getModule(); 323 if (caller != this) { 324 throw new IllegalStateException(caller + " != " + this); 325 } 326 implAddReads(other, true); 327 } 328 return this; 329 } 330 331 /** 332 * Updates this module to read another module. 333 * 334 * @apiNote This method is for Proxy use and white-box testing. 335 */ 336 void implAddReads(Module other) { 337 implAddReads(other, true); 338 } 339 340 /** 341 * Makes the given {@code Module} readable to this module without 342 * notifying the VM. 343 * 344 * @apiNote This method is for VM white-box testing. 345 */ 346 void implAddReadsNoSync(Module other) { 347 implAddReads(other, false); 348 } 349 350 /** 351 * Makes the given {@code Module} readable to this module. 352 * 353 * If {@code syncVM} is {@code true} then the VM is notified. 354 */ 355 private void implAddReads(Module other, boolean syncVM) { 356 357 // nothing to do 358 if (other == this || !this.isNamed()) 359 return; 360 361 // if the other is null then change this module to be loose. 362 if (other == null) { 363 if (syncVM) 364 addReads0(this, null); 365 this.loose = true; 366 return; 367 } 368 369 // check if we already read this module 370 Set<Module> reads = this.reads; 371 if (reads != null && reads.contains(other)) 372 return; 373 374 // update VM first, just in case it fails 375 if (syncVM) 376 addReads0(this, other); 377 378 // add reflective read 379 transientReads.putIfAbsent(this, other, Boolean.TRUE); 380 } 381 382 383 // -- exports -- 384 385 // the packages that are permanently exported 386 // (will be final when the modules are defined in reverse topology order) 387 private volatile Map<String, Set<Module>> exports; 388 389 // additional exports added at run-time 390 // source module (1st key), target module (2nd key), exported packages (value) 391 private static final WeakPairMap<Module, Module, Set<String>> transientExports = 392 new WeakPairMap<>(); 393 394 // the special Module to mean exported to all modules 395 private static final Module EVERYONE_MODULE = new Module(null); 396 private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE); 397 398 // the special Module to mean exported to all unnamed modules 399 private static final Module ALL_UNNAMED_MODULE = new Module(null); 400 401 402 /** 403 * Returns {@code true} if this module exports the given package to at 404 * least the given module. 405 * 406 * <p> This method always return {@code true} when invoked on an unnamed 407 * module. </p> 408 * 409 * <p> This method does not check if the given module reads this module </p> 410 * 411 * @param pn 412 * The package name 413 * @param other 414 * The other module 415 * 416 * @return {@code true} if this module exports the package to at least the 417 * given module 418 */ 419 public boolean isExported(String pn, Module other) { 420 Objects.requireNonNull(pn); 421 Objects.requireNonNull(other); 422 return implIsExported(pn, other); 423 } 424 425 /** 426 * Returns {@code true} if this module exports the given package 427 * unconditionally. 428 * 429 * <p> This method always return {@code true} when invoked on an unnamed 430 * module. </p> 431 * 432 * <p> This method does not check if the given module reads this module </p> 433 * 434 * @param pn 435 * The package name 436 * 437 * @return {@code true} if this module exports the package unconditionally 438 */ 439 public boolean isExported(String pn) { 440 Objects.requireNonNull(pn); 441 return implIsExported(pn, EVERYONE_MODULE); 442 } 443 444 /** 445 * Returns {@code true} if this module exports the given package to the 446 * given module. If the other module is {@code EVERYONE_MODULE} then 447 * this method tests if the package is exported unconditionally. 448 */ 449 private boolean implIsExported(String pn, Module other) { 450 451 // all packages are exported by unnamed modules 452 if (!isNamed()) 453 return true; 454 455 // exported via module declaration/descriptor 456 if (isExportedPermanently(pn, other)) 457 return true; 458 459 // exported via addExports 460 if (isExportedReflectively(pn, other)) 461 return true; 462 463 // not exported or not exported to other 464 return false; 465 } 466 467 /** 468 * Returns {@code true} if this module permanently exports the given 469 * package to the given module. 470 */ 471 private boolean isExportedPermanently(String pn, Module other) { 472 Map<String, Set<Module>> exports = this.exports; 473 if (exports != null) { 474 Set<Module> targets = exports.get(pn); 475 476 if (targets != null) { 477 478 // exported to all modules 479 if (targets.contains(EVERYONE_MODULE)) 480 return true; 481 482 if (other != EVERYONE_MODULE) { 483 // exported to other 484 if (targets.contains(other)) 485 return true; 486 487 // other is an unnamed module && exported to all unnamed 488 if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE)) 489 return true; 490 } 491 492 } 493 } 494 return false; 495 } 496 497 /** 498 * Returns {@code true} if this module reflectively exports the given 499 * package package to the given module. 500 */ 501 private boolean isExportedReflectively(String pn, Module other) { 502 // exported to all modules 503 Set<String> exportedToAll = transientExports.get(this, EVERYONE_MODULE); 504 if (exportedToAll != null && exportedToAll.contains(pn)) 505 return true; 506 507 if (other != EVERYONE_MODULE) { 508 509 // exported to other 510 Set<String> exportedToOther = transientExports.get(this, other); 511 512 if (exportedToOther != null && exportedToOther.contains(pn)) 513 return true; 514 515 // other is an unnamed module && exported to all unnamed 516 if (!other.isNamed()) { 517 Set<String> exportedToAllUnnamed = transientExports.get(this, ALL_UNNAMED_MODULE); 518 if (exportedToAllUnnamed != null && exportedToAllUnnamed.contains(pn)) 519 return true; 520 } 521 } 522 523 return false; 524 } 525 526 527 /** 528 * If the caller's module is this module then update this module to export 529 * package {@code pn} to the given module. 530 * 531 * <p> This method has no effect if the package is already exported to the 532 * given module. If also has no effect if invoked on an unnamed module (as 533 * unnamed modules export all packages). </p> 534 * 535 * @param pn 536 * The package name 537 * @param other 538 * The module 539 * 540 * @return this module 541 * 542 * @throws IllegalArgumentException 543 * If {@code pn} is {@code null}, or this is a named module and the 544 * package {@code pn} is not a package in this module 545 * @throws IllegalStateException 546 * If this is a named module and the caller is not this module 547 */ 548 @CallerSensitive 549 public Module addExports(String pn, Module other) { 550 if (pn == null) 551 throw new IllegalArgumentException("package is null"); 552 Objects.requireNonNull(other); 553 554 if (isNamed()) { 555 Module caller = Reflection.getCallerClass().getModule(); 556 if (caller != this) { 557 throw new IllegalStateException(caller + " != " + this); 558 } 559 implAddExports(pn, other, true); 560 } 561 562 return this; 563 } 564 565 /** 566 * Updates the exports so that package {@code pn} is exported to module 567 * {@code other} but without notifying the VM. 568 * 569 * @apiNote This method is for VM white-box testing. 570 */ 571 void implAddExportsNoSync(String pn, Module other) { 572 if (other == null) 573 other = EVERYONE_MODULE; 574 implAddExports(pn.replace('/', '.'), other, false); 575 } 576 577 /** 578 * Updates the exports so that package {@code pn} is exported to module 579 * {@code other}. 580 * 581 * @apiNote This method is for white-box testing. 582 */ 583 void implAddExports(String pn, Module other) { 584 implAddExports(pn, other, true); 585 } 586 587 /** 588 * Updates the exports so that package {@code pn} is exported to module 589 * {@code other}. 590 * 591 * If {@code syncVM} is {@code true} then the VM is notified. 592 */ 593 private void implAddExports(String pn, Module other, boolean syncVM) { 594 Objects.requireNonNull(other); 595 Objects.requireNonNull(pn); 596 597 // unnamed modules export all packages 598 if (!isNamed()) 599 return; 600 601 // nothing to do if already exported to other 602 if (implIsExported(pn, other)) 603 return; 604 605 // can only export a package in the module 606 if (!containsPackage(pn)) { 607 throw new IllegalArgumentException("package " + pn 608 + " not in contents"); 609 } 610 611 // update VM first, just in case it fails 612 if (syncVM) { 613 String pkgInternalForm = pn.replace('.', '/'); 614 if (other == EVERYONE_MODULE) { 615 addExportsToAll0(this, pkgInternalForm); 616 } else if (other == ALL_UNNAMED_MODULE) { 617 addExportsToAllUnnamed0(this, pkgInternalForm); 618 } else { 619 addExports0(this, pkgInternalForm, other); 620 } 621 } 622 623 // add package name to transientExports if absent 624 transientExports 625 .computeIfAbsent(this, other, (_this, _other) -> new HashSet<>()) 626 .add(pn); 627 } 628 629 630 // -- services -- 631 632 // additional service type (2nd key) that some module (1st key) uses 633 private static final WeakPairMap<Module, Class<?>, Boolean> transientUses 634 = new WeakPairMap<>(); 635 636 /** 637 * If the caller's module is this module then update this module to add a 638 * service dependence on the given service type. This method is intended 639 * for use by frameworks that invoke {@link java.util.ServiceLoader 640 * ServiceLoader} on behalf of other modules or where the framework is 641 * passed a reference to the service type by other code. This method is 642 * a no-op when invoked on an unnamed module. 643 * 644 * <p> This method does not cause {@link 645 * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be 646 * re-run. </p> 647 * 648 * @param st 649 * The service type 650 * 651 * @return this module 652 * 653 * @throws IllegalStateException 654 * If this is a named module and the caller is not this module 655 * 656 * @see #canUse(Class) 657 * @see ModuleDescriptor#uses() 658 */ 659 @CallerSensitive 660 public Module addUses(Class<?> st) { 661 Objects.requireNonNull(st); 662 663 if (isNamed()) { 664 665 Module caller = Reflection.getCallerClass().getModule(); 666 if (caller != this) { 667 throw new IllegalStateException(caller + " != " + this); 668 } 669 670 if (!canUse(st)) { 671 transientUses.putIfAbsent(this, st, Boolean.TRUE); 672 } 673 674 } 675 676 return this; 677 } 678 679 /** 680 * Indicates if this module has a service dependence on the given service 681 * type. This method always returns {@code true} when invoked on an unnamed 682 * module. 683 * 684 * @param st 685 * The service type 686 * 687 * @return {@code true} if this module uses service type {@code st} 688 * 689 * @see #addUses(Class) 690 */ 691 public boolean canUse(Class<?> st) { 692 Objects.requireNonNull(st); 693 694 if (!isNamed()) 695 return true; 696 697 if (descriptor.isAutomatic()) 698 return true; 699 700 // uses was declared 701 if (descriptor.uses().contains(st.getName())) 702 return true; 703 704 // uses added via addUses 705 return transientUses.constainsKeyPair(this, st); 706 } 707 708 709 710 // -- packages -- 711 712 // Additional packages that are added to the module at run-time. 713 // The field is volatile as it may be replaced at run-time 714 private volatile Set<String> extraPackages; 715 716 private boolean containsPackage(String pn) { 717 if (descriptor.packages().contains(pn)) 718 return true; 719 Set<String> extraPackages = this.extraPackages; 720 if (extraPackages != null && extraPackages.contains(pn)) 721 return true; 722 return false; 723 } 724 725 726 /** 727 * Returns an array of the package names of the packages in this module. 728 * 729 * <p> For named modules, the returned array contains an element for each 730 * package in the module. It may contain elements corresponding to packages 731 * added to the module, <a href="Proxy.html#dynamicmodule">dynamic modules</a> 732 * for example, after it was loaded. 733 * 734 * <p> For unnamed modules, this method is the equivalent of invoking the 735 * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of 736 * this module's class loader and returning the array of package names. </p> 737 * 738 * <p> A package name appears at most once in the returned array. </p> 739 * 740 * @apiNote This method returns an array rather than a {@code Set} for 741 * consistency with other {@code java.lang.reflect} types. 742 * 743 * @return an array of the package names of the packages in this module 744 */ 745 public String[] getPackages() { 746 if (isNamed()) { 747 748 Set<String> packages = descriptor.packages(); 749 Set<String> extraPackages = this.extraPackages; 750 if (extraPackages == null) { 751 return packages.toArray(new String[0]); 752 } else { 753 return Stream.concat(packages.stream(), 754 extraPackages.stream()) 755 .toArray(String[]::new); 756 } 757 758 } else { 759 // unnamed module 760 Stream<Package> packages; 761 if (loader == null) { 762 packages = BootLoader.packages(); 763 } else { 764 packages = SharedSecrets.getJavaLangAccess().packages(loader); 765 } 766 return packages.map(Package::getName).toArray(String[]::new); 767 } 768 } 769 770 /** 771 * Add a package to this module. 772 * 773 * @apiNote This method is for Proxy use. 774 * 775 * @apiNote This is an expensive operation, not expected to be used often. 776 * At this time then it does not validate that the package name is a 777 * valid java identifier. 778 */ 779 void addPackage(String pn) { 780 implAddPackage(pn, true); 781 } 782 783 /** 784 * Add a package to this module without notifying the VM. 785 * 786 * @apiNote This method is VM white-box testing. 787 */ 788 void implAddPackageNoSync(String pn) { 789 implAddPackage(pn.replace('/', '.'), false); 790 } 791 792 /** 793 * Add a package to this module. 794 * 795 * If {@code syncVM} is {@code true} then the VM is notified. 796 */ 797 private void implAddPackage(String pn, boolean syncVM) { 798 if (pn.length() == 0) 799 throw new IllegalArgumentException("<unnamed> package not allowed"); 800 801 if (descriptor.packages().contains(pn)) { 802 // already in module 803 return; 804 } 805 806 Set<String> extraPackages = this.extraPackages; 807 if (extraPackages != null && extraPackages.contains(pn)) { 808 // already added 809 return; 810 } 811 synchronized (this) { 812 // recheck under lock 813 extraPackages = this.extraPackages; 814 if (extraPackages != null) { 815 if (extraPackages.contains(pn)) { 816 // already added 817 return; 818 } 819 820 // copy the set 821 extraPackages = new HashSet<>(extraPackages); 822 extraPackages.add(pn); 823 } else { 824 extraPackages = Collections.singleton(pn); 825 } 826 827 // update VM first, just in case it fails 828 if (syncVM) 829 addPackage0(this, pn.replace('.', '/')); 830 831 // replace with new set 832 this.extraPackages = extraPackages; // volatile write 833 } 834 } 835 836 837 // -- creating Module objects -- 838 839 /** 840 * Find the runtime Module corresponding to the given ReadDependence 841 * in the given parent Layer (or its parents). 842 */ 843 private static Module find(ResolvedModule resolvedModule, Layer layer) { 844 Configuration cf = resolvedModule.configuration(); 845 String dn = resolvedModule.name(); 846 847 Module m = null; 848 while (layer != null) { 849 if (layer.configuration() == cf) { 850 Optional<Module> om = layer.findModule(dn); 851 m = om.get(); 852 assert m.getLayer() == layer; 853 break; 854 } 855 layer = layer.parent().orElse(null); 856 } 857 return m; 858 } 859 860 /** 861 * Defines each of the module in the given configuration to the runtime. 862 * 863 * @return a map of module name to runtime {@code Module} 864 * 865 * @throws IllegalArgumentException 866 * If defining any of the modules to the VM fails 867 */ 868 static Map<String, Module> defineModules(Configuration cf, 869 Function<String, ClassLoader> clf, 870 Layer layer) 871 { 872 Map<String, Module> modules = new HashMap<>(); 873 Map<String, ClassLoader> loaders = new HashMap<>(); 874 875 // define each module in the configuration to the VM 876 for (ResolvedModule resolvedModule : cf.modules()) { 877 ModuleReference mref = resolvedModule.reference(); 878 ModuleDescriptor descriptor = mref.descriptor(); 879 String name = descriptor.name(); 880 ClassLoader loader = clf.apply(name); 881 URI uri = mref.location().orElse(null); 882 883 Module m; 884 if (loader == null && name.equals("java.base")) { 885 m = Object.class.getModule(); 886 } else { 887 m = new Module(layer, loader, descriptor, uri); 888 } 889 890 modules.put(name, m); 891 loaders.put(name, loader); 892 } 893 894 // setup readability and exports 895 for (ResolvedModule resolvedModule : cf.modules()) { 896 ModuleReference mref = resolvedModule.reference(); 897 ModuleDescriptor descriptor = mref.descriptor(); 898 899 String mn = descriptor.name(); 900 Module m = modules.get(mn); 901 assert m != null; 902 903 // reads 904 Set<Module> reads = new HashSet<>(); 905 for (ResolvedModule d : resolvedModule.reads()) { 906 Module m2; 907 if (d.configuration() == cf) { 908 String dn = d.reference().descriptor().name(); 909 m2 = modules.get(dn); 910 assert m2 != null; 911 } else { 912 m2 = find(d, layer.parent().orElse(null)); 913 } 914 915 reads.add(m2); 916 917 // update VM view 918 addReads0(m, m2); 919 } 920 m.reads = reads; 921 922 // automatic modules reads all unnamed modules 923 if (descriptor.isAutomatic()) { 924 m.implAddReads(null, true); 925 } 926 927 // exports 928 Map<String, Set<Module>> exports = new HashMap<>(); 929 for (Exports export : descriptor.exports()) { 930 String source = export.source(); 931 String sourceInternalForm = source.replace('.', '/'); 932 933 if (export.isQualified()) { 934 935 // qualified export 936 Set<Module> targets = new HashSet<>(); 937 for (String target : export.targets()) { 938 // only export to modules that are in this configuration 939 Module m2 = modules.get(target); 940 if (m2 != null) { 941 targets.add(m2); 942 addExports0(m, sourceInternalForm, m2); 943 } 944 } 945 if (!targets.isEmpty()) { 946 exports.put(source, targets); 947 } 948 949 } else { 950 951 // unqualified export 952 exports.put(source, EVERYONE); 953 addExportsToAll0(m, sourceInternalForm); 954 } 955 } 956 m.exports = exports; 957 } 958 959 // register the modules in the service catalog if they provide services 960 for (ResolvedModule resolvedModule : cf.modules()) { 961 ModuleReference mref = resolvedModule.reference(); 962 ModuleDescriptor descriptor = mref.descriptor(); 963 Map<String, Provides> services = descriptor.provides(); 964 if (!services.isEmpty()) { 965 String name = descriptor.name(); 966 Module m = modules.get(name); 967 ClassLoader loader = loaders.get(name); 968 ServicesCatalog catalog; 969 if (loader == null) { 970 catalog = BootLoader.getServicesCatalog(); 971 } else { 972 catalog = SharedSecrets.getJavaLangAccess() 973 .createOrGetServicesCatalog(loader); 974 } 975 catalog.register(m); 976 } 977 } 978 979 return modules; 980 } 981 982 983 // -- misc -- 984 985 986 /** 987 * Returns an input stream for reading a resource in this module. Returns 988 * {@code null} if the resource is not in this module or access to the 989 * resource is denied by the security manager. 990 * The {@code name} is a {@code '/'}-separated path name that identifies 991 * the resource. 992 * 993 * <p> If this module is an unnamed module, and the {@code ClassLoader} for 994 * this module is not {@code null}, then this method is equivalent to 995 * invoking the {@link ClassLoader#getResourceAsStream(String) 996 * getResourceAsStream} method on the class loader for this module. 997 * 998 * @param name 999 * The resource name 1000 * 1001 * @return An input stream for reading the resource or {@code null} 1002 * 1003 * @throws IOException 1004 * If an I/O error occurs 1005 * 1006 * @see java.lang.module.ModuleReader#open(String) 1007 */ 1008 public InputStream getResourceAsStream(String name) throws IOException { 1009 Objects.requireNonNull(name); 1010 1011 URL url = null; 1012 1013 if (isNamed()) { 1014 String mn = this.name; 1015 1016 // special-case built-in class loaders to avoid URL connection 1017 if (loader == null) { 1018 return BootLoader.findResourceAsStream(mn, name); 1019 } else if (loader instanceof BuiltinClassLoader) { 1020 return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name); 1021 } 1022 1023 // use SharedSecrets to invoke protected method 1024 url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name); 1025 1026 } else { 1027 1028 // unnamed module 1029 if (loader == null) { 1030 url = BootLoader.findResource(name); 1031 } else { 1032 return loader.getResourceAsStream(name); 1033 } 1034 1035 } 1036 1037 // fallthrough to URL case 1038 if (url != null) { 1039 try { 1040 return url.openStream(); 1041 } catch (SecurityException e) { } 1042 } 1043 1044 return null; 1045 } 1046 1047 /** 1048 * Returns the string representation of this module. For a named module, 1049 * the representation is the string {@code "module"}, followed by a space, 1050 * and then the module name. For an unnamed module, the representation is 1051 * the string {@code "unnamed module"}, followed by a space, and then an 1052 * implementation specific identifier for the unnamed module. 1053 * 1054 * @return The string representation of this module 1055 */ 1056 @Override 1057 public String toString() { 1058 if (isNamed()) { 1059 return "module " + name; 1060 } else { 1061 String id = Integer.toHexString(System.identityHashCode(this)); 1062 return "unnamed module @" + id; 1063 } 1064 } 1065 1066 1067 // -- native methods -- 1068 1069 // JVM_DefineModule 1070 private static native void defineModule0(Module module, 1071 String version, 1072 String location, 1073 String[] pns); 1074 1075 // JVM_AddReadsModule 1076 private static native void addReads0(Module from, Module to); 1077 1078 // JVM_AddModuleExports 1079 private static native void addExports0(Module from, String pn, Module to); 1080 1081 // JVM_AddModuleExportsToAll 1082 private static native void addExportsToAll0(Module from, String pn); 1083 1084 // JVM_AddModuleExportsToAllUnnamed 1085 private static native void addExportsToAllUnnamed0(Module from, String pn); 1086 1087 // JVM_AddModulePackage 1088 private static native void addPackage0(Module m, String pn); 1089 1090 /** 1091 * Register shared secret to provide access to package-private methods 1092 */ 1093 static { 1094 SharedSecrets.setJavaLangReflectModuleAccess( 1095 new JavaLangReflectModuleAccess() { 1096 @Override 1097 public Module defineUnnamedModule(ClassLoader loader) { 1098 return new Module(loader); 1099 } 1100 @Override 1101 public Module defineModule(ClassLoader loader, 1102 ModuleDescriptor descriptor, 1103 URI uri) { 1104 return new Module(null, loader, descriptor, uri); 1105 } 1106 @Override 1107 public void addReads(Module m1, Module m2) { 1108 m1.implAddReads(m2, true); 1109 } 1110 @Override 1111 public void addExports(Module m, String pn, Module other) { 1112 m.implAddExports(pn, Objects.requireNonNull(other), true); 1113 } 1114 @Override 1115 public void addExportsToAll(Module m, String pn) { 1116 m.implAddExports(pn, Module.EVERYONE_MODULE, true); 1117 } 1118 @Override 1119 public void addExportsToAllUnnamed(Module m, String pn) { 1120 m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true); 1121 } 1122 @Override 1123 public void addPackage(Module m, String pn) { 1124 m.implAddPackage(pn, true); 1125 } 1126 }); 1127 } 1128 }