1 /*
   2  Copyright (c) 2017, 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  * @bug 8174954
  27  * @summary Class p5.c5 in module first_mod cannot access p2.c2 in module
  28  *          second_mod, because first_mod cannot read second_mod.  Test that
  29  *          p5.c5 still cannot access p2.c2 even after a read edge is added
  30  *          that enables first_mod to read second_mod.
  31  * @compile ModuleLibrary.java
  32  * @compile p2/c2.java
  33  * @compile p5/c5.java
  34  * @run main/othervm MethodAccessReadTwice
  35  */
  36 
  37 import java.lang.module.Configuration;
  38 import java.lang.module.ModuleDescriptor;
  39 import java.lang.module.ModuleFinder;
  40 import java.lang.ModuleLayer;
  41 import java.lang.Module;
  42 import java.util.HashMap;
  43 import java.util.Map;
  44 import java.util.Set;
  45 
  46 // defines first_mod --> packages p5
  47 // defines second_mod --> package p2, p2 is exported to first_mod
  48 
  49 public class MethodAccessReadTwice {
  50 
  51     // Create a Layer over the boot layer.
  52     // Define modules within this layer to test access between
  53     // publicly defined classes within packages of those modules.
  54     public void createLayerOnBoot() throws Throwable {
  55 
  56         // Define module:     first_mod
  57         // Can read:          java.base
  58         // Packages:          p5
  59         // Packages exported: none
  60         // Packages exported: p5 is exported unqualifiedly
  61 
  62         ModuleDescriptor descriptor_first_mod =
  63                 ModuleDescriptor.newModule("first_mod")
  64                         .requires("java.base")
  65                         .exports("p5")
  66                         .build();
  67 
  68         // Define module:     second_mod
  69         // Can read:          java.base
  70         // Packages:          p2
  71         // Packages exported: p2 is exported to first_mod
  72         ModuleDescriptor descriptor_second_mod =
  73                 ModuleDescriptor.newModule("second_mod")
  74                         .requires("java.base")
  75                         .exports("p2")
  76                         .build();
  77 
  78         // Set up a ModuleFinder containing all modules for this layer
  79         ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod);
  80 
  81         // Resolves "first_mod" and "second_mod"
  82         Configuration cf = ModuleLayer.boot()
  83                 .configuration()
  84                 .resolve(finder, ModuleFinder.of(), Set.of("first_mod", "second_mod"));
  85 
  86         // Map each module to this class loader
  87         Map<String, ClassLoader> map = new HashMap<>();
  88         ClassLoader loader = MethodAccessReadTwice.class.getClassLoader();
  89         map.put("first_mod", loader);
  90         map.put("second_mod", loader);
  91 
  92         // Create Layer that contains first_mod & second_mod
  93         ModuleLayer layer = ModuleLayer.boot().defineModules(cf, map::get);
  94 
  95         Class p2_c2_class = loader.loadClass("p2.c2");
  96         Class p5_c5_class = loader.loadClass("p5.c5");
  97 
  98         Module first_mod = p5_c5_class.getModule();
  99         Module second_mod = p2_c2_class.getModule();
 100 
 101         p5.c5 c5_obj = new p5.c5();
 102         p2.c2 c2_obj = new p2.c2();
 103 
 104         // First access check for p5.c5 --> call to method5 --> tries to access p2.c2
 105         try {
 106             c5_obj.method5(c2_obj); // Should result in IAE
 107             throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2");
 108         } catch (IllegalAccessError e) {
 109             String message = e.getMessage();
 110             if (!(message.contains("cannot access") &&
 111                   message.contains("because module first_mod does not read module second_mod"))) {
 112                 throw new RuntimeException("Wrong message: " + message);
 113             } else {
 114                 System.out.println("Test Succeeded at attempt #1");
 115             }
 116         }
 117 
 118         // Add a read edge from p5/c5's module (first_mod) to second_mod
 119         c5_obj.methodAddReadEdge(p2_c2_class.getModule());
 120 
 121         // Second access check for p5.c5, should have same result as first
 122         try {
 123             c5_obj.method5(c2_obj); // should result in IAE
 124             throw new RuntimeException("Test Failed, access should have been cached above");
 125         } catch (IllegalAccessError e) {
 126             String message = e.getMessage();
 127             if (!(message.contains("cannot access") &&
 128                   message.contains("because module first_mod does not read module second_mod"))) {
 129                 throw new RuntimeException("Wrong message: " + message);
 130             } else {
 131                 System.out.println("Test Succeeded at attempt #2");
 132             }
 133         }
 134     }
 135 
 136     public static void main(String args[]) throws Throwable {
 137       MethodAccessReadTwice test = new MethodAccessReadTwice();
 138       test.createLayerOnBoot();
 139     }
 140 }