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
24package p1;
25
26import java.lang.invoke.MethodHandle;
27import java.lang.invoke.MethodHandles;
28import java.lang.invoke.MethodHandles.Lookup;
29import java.lang.invoke.MethodType;
30
31import static java.lang.invoke.MethodHandles.Lookup.*;
32
33import org.testng.annotations.BeforeTest;
34import org.testng.annotations.Test;
35import static org.testng.Assert.*;
36
37/**
38 * Basic test case for module access checks and Lookup.in.
39 */
40
41@Test
42public 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<?> x500NameClass;   // 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            x500NameClass = Class.forName("sun.security.x509.X500Name");
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, x500NameClass, 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, x500NameClass, 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 no access
143     */
144    public void testFromNamedToNamedModule() throws Exception {
145        Lookup lookup = MethodHandles.lookup().in(q1_Type1);
146        assertTrue(lookup.lookupModes() == 0); // [A0]
147
148        // m1
149        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
150        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
151
152        // m2
153        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
154        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
155
156        // java.base
157        findConstructorExpectingIAE(lookup, Object.class, void.class);
158        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
159
160        // unnamed
161        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
162    }
163
164    /**
165     * Hop to lookup class in an unnamed module
166     *
167     * [A0] has no access
168     */
169    public void testFromNamedToUnnamedModule() throws Exception {
170        Lookup lookup = MethodHandles.lookup().in(unnamedClass);
171        assertTrue(lookup.lookupModes() == 0); // [A0]
172
173        // m1
174        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
175        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
176
177        // m2
178        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
179        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
180
181        // java.base
182        findConstructorExpectingIAE(lookup, Object.class, void.class);
183        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
184
185        // unnamed
186        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
187    }
188
189    /**
190     * Hop from unnamed to named module.
191     *
192     * [A0] retains PUBLIC access
193     */
194    public void testFromUnnamedToNamedModule() throws Exception {
195        Lookup lookup = MethodHandles.lookup();
196        lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1);
197        assertTrue(lookup.lookupModes() == PUBLIC); // A0
198
199        // m1
200        findConstructor(lookup, p1_Type1, void.class);
201        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
202
203        // m2
204        findConstructor(lookup, q1_Type1, void.class);
205        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
206
207        // java.base
208        findConstructor(lookup, Object.class, void.class);
209        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
210
211        // unnamed
212        findConstructor(lookup, unnamedClass, void.class);
213    }
214
215    /**
216     * MethodHandles.publicLookup()
217     *
218     * [A0] has PUBLIC|UNCONDITIONAL access
219     */
220    public void testPublicLookup() throws Exception {
221        Lookup lookup = MethodHandles.publicLookup();
222        assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0
223
224        // m1
225        findConstructor(lookup, p1_Type1, void.class);
226        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
227
228        // m2
229        findConstructor(lookup, q1_Type1, void.class);
230        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
231
232        // java.base
233        findConstructor(lookup, Object.class, void.class);
234        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
235
236        // unnamed
237        findConstructor(lookup, unnamedClass, void.class);
238    }
239
240    /**
241     * Hop from publicLookup to accessible type in java.base
242     */
243    public void testPublicLookupToBaseModule() throws Exception {
244        Lookup lookup = MethodHandles.publicLookup().in(String.class);
245        assertTrue(lookup.lookupModes() == PUBLIC); // A0
246
247        // m1
248        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
249        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
250
251        // m2
252        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
253        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
254
255        // java.base
256        findConstructor(lookup, Object.class, void.class);
257        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
258
259        // unnamed
260        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
261    }
262
263
264    /**
265     * Hop from publicLookup to accessible type in named module.
266     *
267     * [A0] has PUBLIC access
268     */
269    public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
270        Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
271        assertTrue(lookup.lookupModes() == PUBLIC); // A0
272
273        // m1
274        findConstructor(lookup, p1_Type1, void.class);
275        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
276
277        // m2
278        findConstructor(lookup, q1_Type1, void.class);
279        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
280
281        // java.base
282        findConstructor(lookup, Object.class, void.class);
283        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
284
285        // unnamed
286        findConstructor(lookup, unnamedClass, void.class);
287    }
288
289    /**
290     * Teleport from publicLookup to inaccessible type in named module.
291     *
292     * [A0] has no access
293     */
294    public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception {
295        Lookup lookup = MethodHandles.publicLookup().in(p2_Type2);
296        assertTrue(lookup.lookupModes() == 0); // A0
297
298        // m1
299        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
300        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
301
302        // m2
303        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
304        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
305
306        // java.base
307        findConstructorExpectingIAE(lookup, Object.class, void.class);
308        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
309
310        // unnamed
311        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
312    }
313
314    /**
315     * Teleport from publicLookup to public type in unnamed module
316     *
317     * [A0] has PUBLIC access
318     */
319    public void testPublicLookupToUnnamedModule() throws Exception {
320        Lookup lookup = MethodHandles.publicLookup().in(unnamedClass);
321        assertTrue(lookup.lookupModes() == PUBLIC); // A0
322
323        // m1
324        findConstructor(lookup, p1_Type1, void.class);
325        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
326
327        // m2
328        findConstructor(lookup, q1_Type1, void.class);
329        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
330
331        // java.base
332        findConstructor(lookup, Object.class, void.class);
333        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
334
335        // unnamed
336        findConstructor(lookup, unnamedClass, void.class);
337    }
338
339    /**
340     * Invokes Lookup findConstructor with a method type constructored from the
341     * given return and parameter types, expecting IllegalAccessException to be
342     * thrown.
343     */
344    static void findConstructorExpectingIAE(Lookup lookup,
345                                            Class<?> clazz,
346                                            Class<?> rtype,
347                                            Class<?>... ptypes) throws Exception {
348        try {
349            findConstructor(lookup, clazz, rtype, ptypes);
350            assertTrue(false);
351        } catch (IllegalAccessException expected) { }
352    }
353
354    /**
355     * Invokes Lookup findConstructor with a method type constructored from the
356     * given return and parameter types.
357     */
358    static MethodHandle findConstructor(Lookup lookup,
359                                        Class<?> clazz,
360                                        Class<?> rtype,
361                                        Class<?>... ptypes) throws Exception {
362        MethodType mt = MethodType.methodType(rtype, ptypes);
363        return lookup.findConstructor(clazz, mt);
364    }
365}
366