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
24import java.lang.module.Configuration;
25import java.lang.module.ModuleFinder;
26import java.lang.reflect.InvocationHandler;
27import java.lang.reflect.Proxy;
28import java.nio.file.Path;
29import java.nio.file.Paths;
30import java.util.Arrays;
31
32import jdk.test.lib.compiler.CompilerUtils;
33import static jdk.testlibrary.ProcessTools.executeTestJava;
34
35import org.testng.annotations.BeforeTest;
36import org.testng.annotations.Test;
37import static org.testng.Assert.*;
38
39/**
40 * @test
41 * @library /lib/testlibrary /test/lib
42 * @modules jdk.compiler
43 * @build ProxyTest jdk.testlibrary.ProcessTools
44 *        jdk.test.lib.compiler.CompilerUtils
45 * @run testng ProxyLayerTest
46 * @summary Test proxies to implement interfaces in a layer
47 */
48
49public class ProxyLayerTest {
50
51    private static final String TEST_SRC = System.getProperty("test.src");
52    private static final String TEST_CLASSES = System.getProperty("test.classes");
53
54    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
55    private static final Path MODS_DIR = Paths.get("mods");
56    private static final Path CPATH_DIR = Paths.get(TEST_CLASSES);
57
58    // the names of the modules in this test
59    private static String[] modules = new String[] {"m1", "m2", "m3"};
60
61
62    /**
63     * Compiles all modules used by the test
64     */
65    @BeforeTest
66    public void compileAll() throws Exception {
67        for (String mn : modules) {
68            Path msrc = SRC_DIR.resolve(mn);
69            assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString()));
70        }
71    }
72
73    /**
74     * Test proxy implementing interfaces in a layer defined in
75     * an unnamed module
76     */
77    @Test
78    public void testProxyInUnnamed() throws Exception {
79        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
80        ModuleLayer bootLayer = ModuleLayer.boot();
81        Configuration cf = bootLayer
82                .configuration()
83                .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
84        ClassLoader scl = ClassLoader.getSystemClassLoader();
85        ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
86
87        ClassLoader loader = layer.findLoader("m1");
88
89        assertTrue(layer.findModule("m1").isPresent());
90        assertTrue(layer.findModule("m2").isPresent());
91        assertTrue(layer.findModule("m3").isPresent());
92
93        Class<?>[] interfaces = new Class<?>[] {
94            Class.forName("p.one.I", false, loader),
95            Class.forName("p.two.A", false, loader),
96            Class.forName("p.three.P", false, loader),
97        };
98        Object o = Proxy.newProxyInstance(loader, interfaces, handler);
99
100        Class<?> proxyClass = o.getClass();
101        Package pkg = proxyClass.getPackage();
102        assertFalse(proxyClass.getModule().isNamed());
103        assertFalse(pkg.isSealed());
104        assertEquals(proxyClass.getModule().getLayer(), null);
105    }
106
107    /**
108     * Test proxy implementing interfaces in a Layer and defined in a
109     * dynamic module
110     */
111    @Test
112    public void testProxyInDynamicModule() throws Exception {
113        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
114        ModuleLayer bootLayer = ModuleLayer.boot();
115        Configuration cf = bootLayer
116                .configuration()
117                .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
118        ClassLoader scl = ClassLoader.getSystemClassLoader();
119        ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
120
121        ClassLoader loader = layer.findLoader("m1");
122
123        assertTrue(layer.findModule("m1").isPresent());
124        assertTrue(layer.findModule("m2").isPresent());
125        assertTrue(layer.findModule("m3").isPresent());
126
127        Class<?>[] interfaces = new Class<?>[] {
128            Class.forName("p.one.internal.J", false, loader),
129        };
130        Object o = Proxy.newProxyInstance(loader, interfaces, handler);
131        Class<?> proxyClass = o.getClass();
132        Package pkg = proxyClass.getPackage();
133        assertTrue(proxyClass.getModule().isNamed());
134        assertTrue(pkg.isSealed());
135        assertEquals(proxyClass.getModule().getLayer(), null);
136    }
137
138    /**
139     * Test proxy implementing interfaces that the target module has no access
140     */
141    @Test
142    public void testNoReadAccess() throws Exception {
143        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
144        ModuleLayer bootLayer = ModuleLayer.boot();
145        Configuration cf = bootLayer
146                .configuration()
147                .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules));
148        ClassLoader scl = ClassLoader.getSystemClassLoader();
149        ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
150
151        ClassLoader loader = layer.findLoader("m1");
152
153        assertTrue(layer.findModule("m1").isPresent());
154        assertTrue(layer.findModule("m2").isPresent());
155        assertTrue(layer.findModule("m3").isPresent());
156
157        Class<?>[] interfaces = new Class<?>[] {
158                Class.forName("p.one.I", false, loader),
159                Class.forName("p.two.B", false, loader)   // non-public interface but exported package
160        };
161        checkIAE(loader, interfaces);
162    }
163
164    private void checkIAE(ClassLoader loader, Class<?>[] interfaces) {
165        try {
166            Proxy.getProxyClass(loader, interfaces);
167            throw new RuntimeException("Expected IllegalArgumentException thrown");
168        } catch (IllegalArgumentException e) {}
169
170        try {
171            Proxy.newProxyInstance(loader, interfaces, handler);
172            throw new RuntimeException("Expected IllegalArgumentException thrown");
173        } catch (IllegalArgumentException e) {}
174    }
175
176    private final static InvocationHandler handler =
177            (proxy, m, params) -> { throw new RuntimeException(m.toString()); };
178
179}
180