1 /*
   2  * Copyright (c) 2015, 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 package p1;
  25 
  26 import java.lang.invoke.MethodHandle;
  27 import java.lang.invoke.MethodHandles;
  28 import java.lang.invoke.MethodHandles.Lookup;
  29 import java.lang.invoke.MethodType;
  30 
  31 /**
  32  * Basic test case for module access check, supplements AccessControlTest.
  33  *
  34  * The tests consists of two modules:
  35  *
  36  * module m1 { requires m2; exports p1; }
  37  * module m2 { exports q1; }
  38  *
  39  * Both modules read java.base (as every module reads java.base)
  40  *
  41  * module m1 has public types in packages p1 and p2, p2 is not exported.
  42  * module m2 has public types in packages q1 and q2, q2 is not exported.
  43  */
  44 
  45 public class Main {
  46 
  47     static final int MODULE = Lookup.MODULE;
  48 
  49     // Use Class.forName to get classes for test because some
  50     // are not accessible at compile-time
  51 
  52     static final Class<?> p1_Type1;        // m1, exported
  53     static final Class<?> p2_Type2;        // m1, not exported
  54     static final Class<?> q1_Type1;        // m2, exported, m1 reads m2
  55     static final Class<?> q2_Type2;        // m2, not exported, m1 reads m2
  56     static final Class<?> x500NameClass;   // java.base, not exported
  57 
  58     static {
  59         try {
  60             p1_Type1 = Class.forName("p1.Type1");
  61             p2_Type2 = Class.forName("p2.Type2");
  62             q1_Type1 = Class.forName("q1.Type1");
  63             q2_Type2 = Class.forName("q2.Type2");
  64             x500NameClass = Class.forName("sun.security.x509.X500Name");
  65         } catch (ClassNotFoundException e) {
  66             throw new AssertionError(e);
  67         }
  68     }
  69 
  70     public static void main(String[] args) throws Exception {
  71         Lookup lookup, lookup2;
  72 
  73         /**
  74          * MethodHandles.lookup()
  75          * has module access [A0]
  76          * can access all public types in m1 [A1]
  77          * can access public types in packages exported by modules that m1 reads [A2]
  78          * cannot access public types in non-exported modules of modules that m1 reads [A3]
  79          */
  80         lookup = MethodHandles.lookup();
  81         assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0]
  82         findConstructor(lookup, p1_Type1, void.class); // [A1]
  83         findConstructor(lookup, p2_Type2, void.class); // [A1]
  84         findConstructor(lookup, q1_Type1, void.class); // [A2]
  85         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3]
  86         findConstructor(lookup, Object.class, void.class); // [A2]
  87         findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
  88 
  89         /**
  90          * Teleport from MethodHandles.lookup() to lookup class in the same module
  91          * module access is retained [A0]
  92          * can access all public types in m1 [A1]
  93          * can access public types in packages exported by modules that m1 reads [A2]
  94          * cannot access public types in non-exported modules of modules that m1 reads [A3]
  95          */
  96         lookup2 = lookup.in(p2_Type2);
  97         assertTrue((lookup2.lookupModes() & MODULE) == MODULE); // [A0]
  98         findConstructor(lookup2, p1_Type1, void.class); // [A1]
  99         findConstructor(lookup2, p2_Type2, void.class); // [A1]
 100         findConstructor(lookup2, q1_Type1, void.class); // [A2]
 101         findConstructorExpectingIAE(lookup2, q2_Type2, void.class); // [A3]
 102         findConstructor(lookup2, Object.class, void.class); // [A2]
 103         findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A3]
 104 
 105         /**
 106          * Teleport from MethodHandles.lookup() to lookup class in another named module
 107          * has no access [A0]
 108          */
 109         lookup2 = lookup.in(Object.class);
 110         assertTrue(lookup2.lookupModes() == 0); // [A0]
 111         findConstructorExpectingIAE(lookup2, Object.class, void.class);  // [A0]
 112 
 113         /**
 114          * Teleport from MethodHandles.lookup() to lookup class in an unnamed module
 115          * has no access [A0]
 116          */
 117         Class<?> c = MethodHandles.publicLookup().lookupClass();
 118         assertTrue(!c.getModule().isNamed());
 119         lookup2 = lookup.in(c);
 120         assertTrue(lookup2.lookupModes() == 0); // [A0]
 121         findConstructorExpectingIAE(lookup2, Object.class, void.class);
 122 
 123         /**
 124          * MethodHandles.publicLookup()
 125          * has no module access [A0]
 126          * can access public types in exported packages [A1]
 127          * cannot access public types in non-exported packages [A2]
 128          */
 129         lookup = MethodHandles.publicLookup();
 130         assertTrue((lookup.lookupModes() & MODULE) == 0); // [A0]
 131         findConstructor(lookup, p1_Type1, void.class); // [A1]
 132         findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A1]
 133         findConstructor(lookup, q1_Type1, void.class); // [A1]
 134         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
 135         findConstructor(lookup, Object.class, void.class); // [A1]
 136         findConstructorExpectingIAE(lookup, x500NameClass, void.class); // [A2]
 137 
 138         /**
 139          * Teleport from MethodHandles.publicLookup() to lookup class in java.base
 140          * has no module access [A0]
 141          * can access public types in packages exported by java.base [A1]
 142          * cannot access public types in non-exported packages [A2]
 143          * no access to types in other named modules [A3]
 144          */
 145         lookup2 = lookup.in(Object.class);
 146         assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
 147         findConstructor(lookup2, String.class, void.class); // [A1]
 148         findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
 149         findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A3]
 150         findConstructorExpectingIAE(lookup2, q1_Type1, void.class); // [A3]
 151 
 152         /**
 153          * Teleport from MethodHandles.publicLookup() to lookup class in m1
 154          * has no module access [A0]
 155          * can access public types in packages exported by m1, m2 and java.base [A1]
 156          * cannot access public types is non-exported packages [A2]
 157          */
 158         lookup2 = lookup.in(p1_Type1);
 159         assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
 160         findConstructor(lookup2, p1_Type1, void.class);  // [A1]
 161         findConstructor(lookup2, q1_Type1, void.class);  // [A1]
 162         findConstructor(lookup2, Object.class, void.class);  // [A1]
 163         findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A2]
 164         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
 165         findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2]
 166 
 167         /**
 168          * Teleport from MethodHandles.publicLookup() to lookup class in m2
 169          * has no module access [A0]
 170          * can access public types in packages exported by m2 and java.base [A1]
 171          * cannot access public types is non-exported packages or modules that m2 does
 172          *   not read [A2]
 173          */
 174         lookup2 = lookup.in(q1_Type1);
 175         assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0]
 176         findConstructor(lookup2, q1_Type1, void.class); // [A1]
 177         findConstructor(lookup2, Object.class, void.class); // [A1]
 178         findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A2]
 179         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2]
 180         findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class);  // [A2]
 181 
 182         /**
 183          * Teleport from MethodHandles.publicLookup() to lookup class that is not
 184          * in an exported package, should get no access [A0]
 185          */
 186         lookup2 = lookup.in(p2_Type2);
 187         assertTrue(lookup2.lookupModes()  == 0); // [A0]
 188         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A0]
 189     }
 190 
 191     /**
 192      * Invokes Lookup findConstructor with a method type constructored from the
 193      * given return and parameter types, expecting IllegalAccessException to be
 194      * thrown.
 195      */
 196     static MethodHandle findConstructorExpectingIAE(Lookup lookup,
 197                                                     Class<?> clazz,
 198                                                     Class<?> rtype,
 199                                                     Class<?>... ptypes) throws Exception {
 200         try {
 201             findConstructor(lookup, clazz, rtype, ptypes);
 202             throw new RuntimeException("IllegalAccessError expected");
 203         } catch (IllegalAccessException expected) {
 204             return null;
 205         }
 206     }
 207 
 208     /**
 209      * Invokes Lookup findConstructor with a method type constructored from the
 210      * given return and parameter types.
 211      */
 212     static MethodHandle findConstructor(Lookup lookup,
 213                                         Class<?> clazz,
 214                                         Class<?> rtype,
 215                                         Class<?>... ptypes) throws Exception {
 216         MethodType mt = MethodType.methodType(rtype, ptypes);
 217         return lookup.findConstructor(clazz, mt);
 218     }
 219 
 220     static void assertTrue(boolean condition) {
 221         if (!condition)
 222             throw new RuntimeException();
 223     }
 224 
 225 }