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