1 /*
2  * Copyright (c) 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 /**
25  *  @test
26  *  @bug 8235597
27  *  @summary Extend support for -XDaccessInternalAPI to plugin modules
28  *  @library /tools/lib
29  *  @modules jdk.compiler/com.sun.tools.javac.api
30  *           jdk.compiler/com.sun.tools.javac.code
31  *           jdk.compiler/com.sun.tools.javac.main
32  *           jdk.jlink
33  *  @build toolbox.ToolBox toolbox.JavacTask toolbox.JarTask
34  *  @run main InternalAPI
35  */
36 
37 import java.io.IOException;
38 import java.util.List;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.util.spi.ToolProvider;
42 
43 import toolbox.ExecTask;
44 import toolbox.JarTask;
45 import toolbox.JavacTask;
46 import toolbox.Task;
47 import toolbox.TestRunner;
48 import toolbox.ToolBox;
49 
50 public class InternalAPI extends TestRunner {
main(String... args)51     public static void main(String... args) throws Exception {
52         new InternalAPI().run();
53     }
54 
InternalAPI()55     InternalAPI() {
56         super(System.out);
57     }
58 
59     ToolBox tb = new ToolBox();
60 
61     Path pluginJar;
62     Path mclasses;
63 
run()64     void run() throws Exception {
65         Path src = Path.of("src");
66         tb.writeJavaFiles(src,
67             "package p;\n"
68             + "import javax.lang.model.element.*;\n"
69             + "import com.sun.source.util.*;\n"
70             + "import com.sun.tools.javac.code.Symbol.ClassSymbol;\n"
71             + "public class C implements Plugin, TaskListener {\n"
72             + "    public String getName() { return \"TestPlugin\"; }\n"
73             + "    public boolean autoStart() { return true; }\n"
74             + "    public void init(JavacTask task, String... args) {\n"
75             + "        System.out.println(\"C.init \" + java.util.Arrays.toString(args));\n"
76             + "        task.addTaskListener(this);\n"
77             + "    }\n"
78             + "    public void started(TaskEvent e) {\n"
79             + "        TypeElement te = e.getTypeElement();\n"
80             + "        if (te != null) {\n"
81             + "            ClassSymbol sym = (ClassSymbol) te;\n"
82             + "            System.out.println(e.getKind() + \" \" + te + \" \" + sym.kind);\n"
83             + "        }\n"
84             + "    }\n"
85             + "}\n");
86 
87         Path msrc = Path.of("msrc");
88         tb.writeJavaFiles(msrc,
89             "module m {\n"
90             + "    requires jdk.compiler;\n"
91             + "    provides com.sun.source.util.Plugin with p.C;\n"
92             + "}\n");
93 
94         Path classes = Files.createDirectories(Path.of("classes"));
95         new JavacTask(tb)
96             .outdir(classes)
97             .options("--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED")
98             .files(tb.findJavaFiles(src))
99             .run()
100             .writeAll();
101 
102         tb.writeFile(classes.resolve("META-INF").resolve("services").resolve("com.sun.source.util.Plugin"),
103                 "p.C\n");
104 
105         pluginJar = Path.of("plugin.jar");
106         new JarTask(tb, pluginJar)
107                 .baseDir(classes)
108                 .files(".")
109                 .run();
110 
111         mclasses = Files.createDirectories(Path.of("mclasses"));
112         new JavacTask(tb)
113             .outdir(mclasses)
114             .sourcepath(msrc, src)
115             .options("--add-exports", "jdk.compiler/com.sun.tools.javac.code=m")
116             .files(tb.findJavaFiles(msrc))
117             .run()
118             .writeAll();
119 
120         Path hw = Path.of("hw");
121         tb.writeJavaFiles(hw,
122                 "public class HelloWorld {\n"
123                 + "    public static void main(String... args) {\n"
124                 + "        System.out.println(\"Hello World!\");\n"
125                 + "    }\n"
126                 + "}\n");
127 
128         runTests(m -> new Object[] { Path.of(m.getName()) });
129     }
130 
131     @Test
testClassPath(Path base)132     public void testClassPath(Path base) throws Exception {
133         List<String> stdout = new JavacTask(tb)
134                 .options("-XDaccessInternalAPI")
135                 .classpath(pluginJar)
136                 .outdir(Files.createDirectories(base.resolve("out")))
137                 .files(tb.findJavaFiles(Path.of("hw")))
138                 .run()
139                 .writeAll()
140                 .getOutputLines(Task.OutputKind.STDOUT);
141         tb.checkEqual(stdout, List.of("C.init []", "ANALYZE HelloWorld TYP", "GENERATE HelloWorld TYP"));
142     }
143 
144     // negative control test: access fails without the new option
145     @Test
testModuleControl(Path base)146     public void testModuleControl(Path base) throws Exception {
147         try {
148             new JavacTask(tb)
149                     .options("--processor-module-path", mclasses.toString())
150                     .outdir(Files.createDirectories(base.resolve("out")))
151                     .files(tb.findJavaFiles(Path.of("hw")))
152                     .run()
153                     .writeAll();
154             throw new Exception("expected exception not thrown");
155         } catch (Exception e) {
156             System.out.println("*** " + e);
157             String msg = e.getMessage();
158             if (!msg.contains("java.lang.IllegalAccessError: class p.C (in module m) "
159                 + "cannot access class com.sun.tools.javac.code.Symbol$ClassSymbol (in module jdk.compiler)")) {
160                 throw new Exception("expected exception not found");
161             }
162         }
163     }
164 
165     // positive test: access succeeds with option for modules on modulepath
166     @Test
testModulePath(Path base)167     public void testModulePath(Path base) throws IOException {
168         List<String> stdout = new JavacTask(tb)
169                 .options("--processor-module-path", mclasses.toString(),
170                         "-XDaccessInternalAPI")
171                 .outdir(Files.createDirectories(base.resolve("out")))
172                 .files(tb.findJavaFiles(Path.of("hw")))
173                 .run()
174                 .writeAll()
175                 .getOutputLines(Task.OutputKind.STDOUT);
176         tb.checkEqual(stdout, List.of("C.init []", "ANALYZE HelloWorld TYP", "GENERATE HelloWorld TYP"));
177     }
178 
179     // positive test: access succeeds with option for modules in image
180     @Test
testImage(Path base)181     public void testImage(Path base) throws Exception {
182         Path tmpJDK = base.resolve("tmpJDK");
183         ToolProvider jlink = ToolProvider.findFirst("jlink")
184                 .orElseThrow(() -> new Exception("cannot find jlink"));
185         jlink.run(System.out, System.err,
186                 "--module-path", mclasses.toString(),
187                 "--add-modules", "jdk.compiler,jdk.zipfs,m",
188                 "--output", tmpJDK.toString());
189 
190         String suffix = tb.isWindows() ? ".exe" : "";
191         List<String> stdout = new ExecTask(tb, tmpJDK.resolve("bin").resolve("javac" + suffix))
192                 .args("-d", Files.createDirectories(base.resolve("out")).toString(),
193                         "-XDaccessInternalAPI",
194                         Path.of("hw").resolve("HelloWorld.java").toString())
195                 .run()
196                 .writeAll()
197                 .getOutputLines(Task.OutputKind.STDOUT);
198         tb.checkEqual(stdout, List.of("C.init []", "ANALYZE HelloWorld TYP", "GENERATE HelloWorld TYP"));
199     }
200 }
201 
202