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