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