1 /*
   2  * Copyright (c) 2016, 2018, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary class p1.c1 defined in m1x tries to access p2.c2 defined in unnamed module.
  27  * @library /test/lib
  28  * @modules java.base/jdk.internal.misc
  29  * @modules java.base/jdk.internal.module
  30  * @compile myloaders/MyDiffClassLoader.java
  31  * @compile p2/c2.java
  32  * @compile p1/c1.java
  33  * @compile p1/c1ReadEdgeDiffLoader.java
  34  * @compile p1/c1Loose.java
  35  * @run main/othervm -Xbootclasspath/a:. DiffCL_Umod
  36  */
  37 
  38 import static jdk.test.lib.Asserts.*;
  39 
  40 import java.lang.module.Configuration;
  41 import java.lang.module.ModuleDescriptor;
  42 import java.lang.module.ModuleFinder;
  43 import java.util.HashMap;
  44 import java.util.Map;
  45 import java.util.Set;
  46 import myloaders.MyDiffClassLoader;
  47 
  48 //
  49 // ClassLoader1 --> defines m1x --> packages p1
  50 //                  package p1 in m1x is exported unqualifiedly
  51 //
  52 // class p1.c1 defined in m1x tries to access p2.c2 defined in
  53 // in unnamed module.
  54 //
  55 // Three access attempts occur in this test:
  56 //   1. The first access is not allowed because a strict module
  57 //      cannot read an unnamed module.
  58 //   2. In this scenario a strict module establishes readability
  59 //      to the particular unnamed module it is trying to access.
  60 //      Access is allowed.
  61 //   3. Module m1x in the test_looseModuleLayer() method
  62 //      is transitioned to a loose module, access
  63 //      to all unnamed modules is allowed.
  64 //
  65 public class DiffCL_Umod {
  66 
  67  // Create layers over the boot layer to test different
  68  // accessing scenarios of a named module to an unnamed module.
  69 
  70  // Module m1x is a strict module and has not established
  71  // readability to an unnamed module that p2.c2 is defined in.
  72  public void test_strictModuleLayer() throws Throwable {
  73 
  74      // Define module:     m1x
  75      // Can read:          java.base
  76      // Packages:          p1
  77      // Packages exported: p1 is exported unqualifiedly
  78      ModuleDescriptor descriptor_m1x =
  79              ModuleDescriptor.newModule("m1x")
  80                      .requires("java.base")
  81                      .exports("p1")
  82                      .build();
  83 
  84      // Set up a ModuleFinder containing all modules for this layer.
  85      ModuleFinder finder = ModuleLibrary.of(descriptor_m1x);
  86 
  87      // Resolves "m1x"
  88      Configuration cf = ModuleLayer.boot()
  89              .configuration()
  90              .resolve(finder, ModuleFinder.of(), Set.of("m1x"));
  91 
  92      MyDiffClassLoader.loader1 = new MyDiffClassLoader();
  93      MyDiffClassLoader.loader2 = new MyDiffClassLoader();
  94 
  95      // map module m1x to class loader.
  96      // class c2 will be loaded in an unnamed module/loader2
  97      // to achieve differing class loaders.
  98      Map<String, ClassLoader> map = new HashMap<>();
  99      map.put("m1x", MyDiffClassLoader.loader1);
 100 
 101      // Create layer that contains m1x
 102      ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
 103 
 104      assertTrue(layer.findLoader("m1x") == MyDiffClassLoader.loader1);
 105      assertTrue(layer.findLoader("java.base") == null);
 106 
 107      // now use the same loader to load class p1.c1
 108      Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1");
 109 
 110      // Attempt access
 111      try {
 112          p1_c1_class.newInstance();
 113          throw new RuntimeException("Test Failed, strict module m1x should not be able " +
 114                                     "to access public type p2.c2 defined in unnamed module");
 115      } catch (IllegalAccessError e) {
 116      }
 117 }
 118 
 119  // Module m1x is a strict module and has established
 120  // readability to an unnamed module that p2.c2 is defined in.
 121  public void test_strictModuleUnnamedReadableLayer() throws Throwable {
 122 
 123      // Define module:     m1x
 124      // Can read:          java.base
 125      // Packages:          p1
 126      // Packages exported: p1 is exported unqualifiedly
 127      ModuleDescriptor descriptor_m1x =
 128              ModuleDescriptor.newModule("m1x")
 129                      .requires("java.base")
 130                      .exports("p1")
 131                      .build();
 132 
 133      // Set up a ModuleFinder containing all modules for this layer.
 134      ModuleFinder finder = ModuleLibrary.of(descriptor_m1x);
 135 
 136      // Resolves "m1x"
 137      Configuration cf = ModuleLayer.boot()
 138              .configuration()
 139              .resolve(finder, ModuleFinder.of(), Set.of("m1x"));
 140 
 141      MyDiffClassLoader.loader1 = new MyDiffClassLoader();
 142      MyDiffClassLoader.loader2 = new MyDiffClassLoader();
 143 
 144      // map module m1x to class loader.
 145      // class c2 will be loaded in an unnamed module/loader2
 146      // to achieve differing class loaders.
 147      Map<String, ClassLoader> map = new HashMap<>();
 148      map.put("m1x", MyDiffClassLoader.loader1);
 149 
 150      // Create layer that contains m1x
 151      ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
 152 
 153      assertTrue(layer.findLoader("m1x") == MyDiffClassLoader.loader1);
 154      assertTrue(layer.findLoader("java.base") == null);
 155 
 156      // now use the same loader to load class p1.c1ReadEdgeDiffLoader
 157      Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1ReadEdgeDiffLoader");
 158 
 159      try {
 160         // Read edge between m1x and the unnamed module that loads p2.c2 is established in
 161         // c1ReadEdgeDiffLoader's ctor before attempting access.
 162         p1_c1_class.newInstance();
 163      } catch (IllegalAccessError e) {
 164          throw new RuntimeException("Test Failed, module m1x has established readability to p2/c2 loader's " +
 165                                     "unnamed module, access should be allowed: " + e.getMessage());
 166      }
 167  }
 168 
 169  // Module m1x is a loose module and thus can read all unnamed modules.
 170  public void test_looseModuleLayer() throws Throwable {
 171 
 172      // Define module:     m1x
 173      // Can read:          java.base
 174      // Packages:          p1
 175      // Packages exported: p1 is exported unqualifiedly
 176      ModuleDescriptor descriptor_m1x =
 177              ModuleDescriptor.newModule("m1x")
 178                      .requires("java.base")
 179                      .exports("p1")
 180                      .build();
 181 
 182      // Set up a ModuleFinder containing all modules for this layer.
 183      ModuleFinder finder = ModuleLibrary.of(descriptor_m1x);
 184 
 185      // Resolves "m1x"
 186      Configuration cf = ModuleLayer.boot()
 187              .configuration()
 188              .resolve(finder, ModuleFinder.of(), Set.of("m1x"));
 189 
 190      MyDiffClassLoader.loader1 = new MyDiffClassLoader();
 191      MyDiffClassLoader.loader2 = new MyDiffClassLoader();
 192 
 193      // map module m1x to class loader.
 194      // class c2 will be loaded in an unnamed module/loader2
 195      // to achieve differing class loaders.
 196      Map<String, ClassLoader> map = new HashMap<>();
 197      map.put("m1x", MyDiffClassLoader.loader1);
 198 
 199      // Create layer that contains m1x
 200      ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
 201 
 202      assertTrue(layer.findLoader("m1x") == MyDiffClassLoader.loader1);
 203      assertTrue(layer.findLoader("java.base") == null);
 204 
 205      // now use the same loader to load class p1.c1Loose
 206      Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1Loose");
 207 
 208      // change m1x to read all unnamed modules
 209      Module m1x = layer.findModule("m1x").get();
 210      jdk.internal.module.Modules.addReadsAllUnnamed(m1x);
 211 
 212      try {
 213          p1_c1_class.newInstance();
 214      } catch (IllegalAccessError e) {
 215          throw new RuntimeException("Test Failed, loose module m1x should be able to access " +
 216                                     "public type p2.c2 defined in unnamed module: " + e.getMessage());
 217      }
 218  }
 219 
 220  public static void main(String args[]) throws Throwable {
 221    DiffCL_Umod test = new DiffCL_Umod();
 222    test.test_strictModuleLayer();                // access denied
 223    test.test_strictModuleUnnamedReadableLayer(); // access allowed
 224    test.test_looseModuleLayer();                 // access allowed
 225  }
 226 }