1 /*
   2  * Copyright (c) 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 /*
  27  * @test
  28  * @summary class p1.c1 defined in m1 tries to access p2.c2 defined in unnamed module.
  29  * @library /test/lib
  30  * @modules java.base/jdk.internal.misc
  31  * @modules java.base/jdk.internal.module
  32  * @compile myloaders/MySameClassLoader.java
  33  * @compile p2/c2.java
  34  * @compile p1/c1.java
  35  * @compile p1/c1ReadEdge.java
  36  * @compile p1/c1Loose.java
  37  * @run main/othervm -Xbootclasspath/a:. Umod
  38  */
  39 
  40 import static jdk.test.lib.Asserts.*;
  41 
  42 import java.lang.reflect.Layer;
  43 import java.lang.module.Configuration;
  44 import java.lang.module.ModuleDescriptor;
  45 import java.lang.module.ModuleFinder;
  46 import java.lang.reflect.Module;
  47 import java.util.HashMap;
  48 import java.util.Map;
  49 import java.util.Set;
  50 import myloaders.MySameClassLoader;
  51 
  52 //
  53 // ClassLoader1 --> defines m1 --> packages p1
  54 //                  package p1 in m1 is exported unqualifiedly
  55 //
  56 // class p1.c1 defined in m1 tries to access p2.c2 defined in
  57 // in unnamed module.
  58 //
  59 // Three access attempts occur in this test:
  60 //   1. The first access is not allowed because a strict module
  61 //      cannot read an unnamed module.
  62 //   2. In this scenario a strict module establishes readability
  63 //      to the particular unnamed module it is trying to access.
  64 //      Access is allowed.
  65 //   3. Module m1 in the test_looseModuleLayer() method
  66 //      is transitioned to a loose module, access
  67 //      to all unnamed modules is allowed.
  68 //
  69 public class Umod {
  70 
  71  // Create Layers over the boot layer to test different
  72  // accessing scenarios of a named module to an unnamed module.
  73 
  74  // Module m1 is a strict module and has not established
  75  // readability to an unnamed module that p2.c2 is defined in.
  76  public void test_strictModuleLayer() throws Throwable {
  77 
  78      // Define module:     m1
  79      // Can read:          java.base
  80      // Packages:          p1
  81      // Packages exported: p1 is exported unqualifiedly
  82      ModuleDescriptor descriptor_m1 =
  83              new ModuleDescriptor.Builder("m1")
  84                      .requires("java.base")
  85                      .exports("p1")
  86                      .build();
  87 
  88      // Set up a ModuleFinder containing all modules for this layer.
  89      ModuleFinder finder = ModuleLibrary.of(descriptor_m1);
  90 
  91      // Resolves "m1"
  92      Configuration cf = Layer.boot()
  93              .configuration()
  94              .resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
  95 
  96      // map module m1 to class loader.
  97      // class c2 will be loaded in an unnamed module/loader.
  98      MySameClassLoader loader = new MySameClassLoader();
  99      Map<String, ClassLoader> map = new HashMap<>();
 100      map.put("m1", loader);
 101 
 102      // Create Layer that contains m1
 103      Layer layer = Layer.boot().defineModules(cf, map::get);
 104 
 105      assertTrue(layer.findLoader("m1") == loader);
 106      assertTrue(layer.findLoader("java.base") == null);
 107 
 108      // now use the same loader to load class p1.c1
 109      Class p1_c1_class = loader.loadClass("p1.c1");
 110 
 111      // Attempt access
 112      try {
 113          p1_c1_class.newInstance();
 114          throw new RuntimeException("Test Failed, strict module m1, type p1.c1, should not be able " +
 115                                     "to access public type p2.c2 defined in unnamed module");
 116      } catch (IllegalAccessError e) {
 117      }
 118  }
 119 
 120  // Module m1 is a strict module and has established
 121  // readability to an unnamed module that p2.c2 is defined in.
 122  public void test_strictModuleUnnamedReadableLayer() throws Throwable {
 123 
 124      // Define module:     m1
 125      // Can read:          java.base
 126      // Packages:          p1
 127      // Packages exported: p1 is exported unqualifiedly
 128      ModuleDescriptor descriptor_m1 =
 129              new ModuleDescriptor.Builder("m1")
 130                      .requires("java.base")
 131                      .exports("p1")
 132                      .build();
 133 
 134      // Set up a ModuleFinder containing all modules for this layer.
 135      ModuleFinder finder = ModuleLibrary.of(descriptor_m1);
 136 
 137      // Resolves "m1"
 138      Configuration cf = Layer.boot()
 139              .configuration()
 140              .resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
 141 
 142      MySameClassLoader loader = new MySameClassLoader();
 143      // map module m1 to class loader.
 144      // class c2 will be loaded in an unnamed module/loader.
 145      Map<String, ClassLoader> map = new HashMap<>();
 146      map.put("m1", loader);
 147 
 148      // Create Layer that contains m1
 149      Layer layer = Layer.boot().defineModules(cf, map::get);
 150 
 151      assertTrue(layer.findLoader("m1") == loader);
 152      assertTrue(layer.findLoader("java.base") == null);
 153 
 154      // now use the same loader to load class p1.c1ReadEdge
 155      Class p1_c1_class = loader.loadClass("p1.c1ReadEdge");
 156 
 157      try {
 158        // Read edge between m1 and the unnamed module that loads p2.c2 is established in
 159        // c1ReadEdge's ctor before attempting access.
 160        p1_c1_class.newInstance();
 161      } catch (IllegalAccessError e) {
 162          throw new RuntimeException("Test Failed, strict module m1, type p1.c1ReadEdge, should be able to acccess public type " +
 163                                     "p2.c2 defined in unnamed module: " + e.getMessage());
 164      }
 165 }
 166 
 167  // Module m1 is a loose module and thus can read all unnamed modules.
 168  public void test_looseModuleLayer() throws Throwable {
 169 
 170      // Define module:     m1
 171      // Can read:          java.base
 172      // Packages:          p1
 173      // Packages exported: p1 is exported unqualifiedly
 174      ModuleDescriptor descriptor_m1 =
 175              new ModuleDescriptor.Builder("m1")
 176                      .requires("java.base")
 177                      .exports("p1")
 178                      .build();
 179 
 180      // Set up a ModuleFinder containing all modules for this layer.
 181      ModuleFinder finder = ModuleLibrary.of(descriptor_m1);
 182 
 183      // Resolves "m1"
 184      Configuration cf = Layer.boot()
 185              .configuration()
 186              .resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
 187 
 188      MySameClassLoader loader = new MySameClassLoader();
 189      // map module m1 to class loader.
 190      // class c2 will be loaded in an unnamed module/loader.
 191      Map<String, ClassLoader> map = new HashMap<>();
 192      map.put("m1", loader);
 193 
 194      // Create Layer that contains m1
 195      Layer layer = Layer.boot().defineModules(cf, map::get);
 196 
 197      assertTrue(layer.findLoader("m1") == loader);
 198      assertTrue(layer.findLoader("java.base") == null);
 199 
 200      // now use the same loader to load class p1.c1Loose
 201      Class p1_c1_class = loader.loadClass("p1.c1Loose");
 202 
 203      // change m1 to read all unnamed modules
 204      Module m1 = layer.findModule("m1").get();
 205      jdk.internal.module.Modules.addReadsAllUnnamed(m1);
 206 
 207      try {
 208          p1_c1_class.newInstance();
 209      } catch (IllegalAccessError e) {
 210          throw new RuntimeException("Test Failed, strict module m1, type p1.c1Loose, should be able to acccess public type " +
 211                                     "p2.c2 defined in unnamed module: " + e.getMessage());
 212      }
 213  }
 214 
 215  public static void main(String args[]) throws Throwable {
 216    Umod test = new Umod();
 217    test.test_strictModuleLayer();                // access denied
 218    test.test_strictModuleUnnamedReadableLayer(); // access allowed
 219    test.test_looseModuleLayer();                 // access allowed
 220  }
 221 }