1 /*
   2  * Copyright (c) 2015, 2019, 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 import static java.lang.invoke.MethodHandles.Lookup.*;
  32 
  33 import org.testng.annotations.BeforeTest;
  34 import org.testng.annotations.Test;
  35 import static org.testng.Assert.*;
  36 
  37 /**
  38  * Basic test case for module access checks and Lookup.in.
  39  */
  40 
  41 @Test
  42 public class Main {
  43 
  44     private Class<?> p1_Type1;        // m1, exported
  45     private Class<?> p2_Type2;        // m1, not exported
  46     private Class<?> q1_Type1;        // m2, exported
  47     private Class<?> q2_Type2;        // m2, not exported
  48     private Class<?> signalClass;     // java.base, not exported
  49     private Class<?> unnamedClass;    // class in unnamed module
  50 
  51     @BeforeTest
  52     public void setup() throws Exception {
  53         try {
  54             p1_Type1 = Class.forName("p1.Type1");
  55             p2_Type2 = Class.forName("p2.Type2");
  56             q1_Type1 = Class.forName("q1.Type1");
  57             q2_Type2 = Class.forName("q2.Type2");
  58             signalClass = Class.forName("jdk.internal.misc.Signal");
  59             unnamedClass = Class.forName("Unnamed");
  60         } catch (ClassNotFoundException e) {
  61             throw new AssertionError(e);
  62         }
  63 
  64         // check setup
  65         Module m1 = ModuleLayer.boot().findModule("m1").orElse(null);
  66         assertNotNull(m1);
  67         assertTrue(p1_Type1.getModule() == m1);
  68         assertTrue(p2_Type2.getModule() == m1);
  69         assertTrue(m1.isExported("p1"));
  70         assertFalse(m1.isExported("p2"));
  71 
  72         Module m2 = ModuleLayer.boot().findModule("m2").orElse(null);
  73         assertNotNull(m2);
  74         assertTrue(q1_Type1.getModule() == m2);
  75         assertTrue(q2_Type2.getModule() == m2);
  76         assertTrue(m2.isExported("q1"));
  77         assertFalse(m2.isExported("q2"));
  78 
  79         Module unnamedModule = unnamedClass.getModule();
  80         assertFalse(unnamedModule.isNamed());
  81 
  82         // m1 needs to read unnamed module
  83         Main.class.getModule().addReads(unnamedModule);
  84     }
  85 
  86     /**
  87      * MethodHandles.lookup()
  88      *
  89      * [A0] has module access
  90      * [A1] can access all public types in m1
  91      * [A2] can access public types in packages exported by modules that m1 reads
  92      * [A3] cannot access public types in non-exported modules of modules that m1 reads
  93      */
  94     public void testLookup() throws Exception {
  95         Lookup lookup = MethodHandles.lookup();
  96         assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0]
  97 
  98         // m1
  99         findConstructor(lookup, p1_Type1, void.class); // [A1]
 100         findConstructor(lookup, p2_Type2, void.class); // [A1]
 101 
 102         // m2
 103         findConstructor(lookup, q1_Type1, void.class); // [A2]
 104         findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3]
 105 
 106         // java.base
 107         findConstructor(lookup, Object.class, void.class); // [A2]
 108         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // [A3]
 109 
 110         // unnamed
 111         findConstructor(lookup, unnamedClass, void.class);  // [A3]
 112     }
 113 
 114     /**
 115      * Hop to lookup class in the same module
 116      *
 117      * [A0] module and public access is not lost
 118      */
 119     public void testToSameModule() throws Exception {
 120         Lookup lookup = MethodHandles.lookup().in(p2_Type2);
 121         assertTrue(lookup.lookupModes() == (MODULE|PUBLIC)); // [A0]
 122 
 123         // m1
 124         findConstructor(lookup, p1_Type1, void.class);
 125         findConstructor(lookup, p2_Type2, void.class);
 126 
 127         // m2
 128         findConstructor(lookup, q1_Type1, void.class);
 129         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 130 
 131         // java.base
 132         findConstructor(lookup, Object.class, void.class);
 133         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 134 
 135         // unnamed
 136         findConstructor(lookup, unnamedClass, void.class);
 137     }
 138 
 139     /**
 140      * Hop to lookup class in another named module
 141      *
 142      * [A0] has PUBLIC access if accessible; otherwise no access
 143      * [A1] old lookup class becomes previous lookup class
 144      */
 145     public void testFromNamedToNamedModule() throws Exception {
 146         // m2/q1_Type1 is accessible to m1 whereas m2/q_Type2 is not accessible
 147         Lookup lookup = MethodHandles.lookup().in(q1_Type1);
 148         assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
 149         assertTrue(lookup.previousLookupClass() == Main.class); // [A1]
 150 
 151         Lookup lookup2 = MethodHandles.lookup().in(q2_Type2);
 152         assertTrue(lookup2.lookupModes() == 0);      // [A0]
 153         assertTrue(lookup2.previousLookupClass() == Main.class); // [A1]
 154 
 155         // m1
 156         findConstructorExpectingIAE(lookup, p1_Type1, void.class);
 157         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 158 
 159         findConstructorExpectingIAE(lookup2, p1_Type1, void.class);
 160         findConstructorExpectingIAE(lookup2, p2_Type2, void.class);
 161 
 162         // m2
 163         findConstructor(lookup, q1_Type1, void.class);  // m2/q1 is exported
 164         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 165 
 166         findConstructorExpectingIAE(lookup2, q1_Type1, void.class);
 167         findConstructorExpectingIAE(lookup2, q2_Type2, void.class);
 168 
 169         // java.base
 170         findConstructor(lookup, Object.class, void.class);
 171         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 172 
 173         findConstructorExpectingIAE(lookup2, Object.class, void.class);
 174         findConstructorExpectingIAE(lookup2, signalClass, void.class, String.class);
 175 
 176         // unnamed
 177         findConstructorExpectingIAE(lookup, unnamedClass, void.class);
 178 
 179         findConstructorExpectingIAE(lookup2, unnamedClass, void.class);
 180 
 181     }
 182 
 183     /**
 184      * Hop to lookup class in an unnamed module
 185      *
 186      * [A0] has PUBLIC access
 187      */
 188     public void testFromNamedToUnnamedModule() throws Exception {
 189         Lookup lookup = MethodHandles.lookup().in(unnamedClass);
 190         assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
 191 
 192         // m1
 193         findConstructor(lookup, p1_Type1, void.class);      // p1 is exported
 194         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 195 
 196         // m2
 197         findConstructor(lookup, q1_Type1, void.class);
 198         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 199 
 200         // java.base
 201         findConstructor(lookup, Object.class, void.class);
 202         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 203 
 204         // unnamed
 205         findConstructor(lookup, unnamedClass, void.class);
 206     }
 207 
 208     /**
 209      * Hop from unnamed to named module.
 210      *
 211      * [A0] retains PUBLIC access
 212      */
 213     public void testFromUnnamedToNamedModule() throws Exception {
 214         Lookup lookup = MethodHandles.lookup();
 215         lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1);
 216         assertTrue(lookup.lookupModes() == PUBLIC); // A0
 217 
 218         // m1
 219         findConstructor(lookup, p1_Type1, void.class);
 220         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 221 
 222         // m2
 223         findConstructor(lookup, q1_Type1, void.class);
 224         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 225 
 226         // java.base
 227         findConstructor(lookup, Object.class, void.class);
 228         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 229 
 230         // unnamed
 231         findConstructor(lookup, unnamedClass, void.class);
 232     }
 233 
 234     /**
 235      * MethodHandles.publicLookup()
 236      *
 237      * [A0] has UNCONDITIONAL access
 238      */
 239     public void testPublicLookup() throws Exception {
 240         Lookup lookup = MethodHandles.publicLookup();
 241         assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 242 
 243         // m1
 244         findConstructor(lookup, p1_Type1, void.class);
 245         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 246 
 247         // m2
 248         findConstructor(lookup, q1_Type1, void.class);
 249         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 250 
 251         // java.base
 252         findConstructor(lookup, Object.class, void.class);
 253         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 254 
 255         // unnamed
 256         findConstructor(lookup, unnamedClass, void.class);
 257     }
 258 
 259     /**
 260      * Hop from publicLookup to accessible type in java.base
 261      *
 262      * [A0] has UNCONDITIONAL access
 263      */
 264     public void testPublicLookupToBaseModule() throws Exception {
 265         Lookup lookup = MethodHandles.publicLookup().in(String.class);
 266         assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 267 
 268         // m1
 269         findConstructor(lookup, p1_Type1, void.class);
 270         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 271 
 272         // m2
 273         findConstructor(lookup, q1_Type1, void.class);
 274         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 275 
 276         // java.base
 277         findConstructor(lookup, Object.class, void.class);
 278         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 279 
 280         // unnamed
 281         findConstructor(lookup, unnamedClass, void.class);
 282     }
 283 
 284 
 285     /**
 286      * Hop from publicLookup to accessible type in named module.
 287      *
 288      * [A0] has UNCONDITIONAL access
 289      */
 290     public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
 291         Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
 292         assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 293 
 294         // m1
 295         findConstructor(lookup, p1_Type1, void.class);
 296         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 297 
 298         // m2
 299         findConstructor(lookup, q1_Type1, void.class);
 300         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 301 
 302         // java.base
 303         findConstructor(lookup, Object.class, void.class);
 304         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 305 
 306         // unnamed
 307         findConstructor(lookup, unnamedClass, void.class);
 308     }
 309 
 310     /**
 311      * Teleport from publicLookup to inaccessible type in named module.
 312      *
 313      * [A0] has no access
 314      */
 315     public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception {
 316         Lookup lookup = MethodHandles.publicLookup().in(p2_Type2);
 317         assertTrue(lookup.lookupModes() == 0); // A0
 318 
 319         // m1
 320         findConstructorExpectingIAE(lookup, p1_Type1, void.class);
 321         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 322 
 323         // m2
 324         findConstructorExpectingIAE(lookup, q1_Type1, void.class);
 325         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 326 
 327         // java.base
 328         findConstructorExpectingIAE(lookup, Object.class, void.class);
 329         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 330 
 331         // unnamed
 332         findConstructorExpectingIAE(lookup, unnamedClass, void.class);
 333     }
 334 
 335     /**
 336      * Teleport from publicLookup to public type in unnamed module
 337      *
 338      * [A0] has UNCONDITIONAL access
 339      */
 340     public void testPublicLookupToUnnamedModule() throws Exception {
 341         Lookup lookup = MethodHandles.publicLookup().in(unnamedClass);
 342         assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 343 
 344         // m1
 345         findConstructor(lookup, p1_Type1, void.class);
 346         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 347 
 348         // m2
 349         findConstructor(lookup, q1_Type1, void.class);
 350         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 351 
 352         // java.base
 353         findConstructor(lookup, Object.class, void.class);
 354         findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 355 
 356         // unnamed
 357         findConstructor(lookup, unnamedClass, void.class);
 358     }
 359 
 360     /**
 361      * Invokes Lookup findConstructor with a method type constructored from the
 362      * given return and parameter types, expecting IllegalAccessException to be
 363      * thrown.
 364      */
 365     static void findConstructorExpectingIAE(Lookup lookup,
 366                                             Class<?> clazz,
 367                                             Class<?> rtype,
 368                                             Class<?>... ptypes) throws Exception {
 369         try {
 370             findConstructor(lookup, clazz, rtype, ptypes);
 371             assertTrue(false);
 372         } catch (IllegalAccessException expected) { }
 373     }
 374 
 375     /**
 376      * Invokes Lookup findConstructor with a method type constructored from the
 377      * given return and parameter types.
 378      */
 379     static MethodHandle findConstructor(Lookup lookup,
 380                                         Class<?> clazz,
 381                                         Class<?> rtype,
 382                                         Class<?>... ptypes) throws Exception {
 383         MethodType mt = MethodType.methodType(rtype, ptypes);
 384         return lookup.findConstructor(clazz, mt);
 385     }
 386 }