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&trade; 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 }