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 /**
25  * @test
26  * @library /test/lib
27  * @modules java.base/jdk.internal.module
28  *          jdk.compiler
29  *          jdk.jlink
30  * @build ModuleReaderTest
31  *        jdk.test.lib.compiler.CompilerUtils
32  *        jdk.test.lib.util.JarUtils
33  * @run testng ModuleReaderTest
34  * @summary Basic tests for java.lang.module.ModuleReader
35  */
36 
37 import java.io.File;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.lang.module.ModuleFinder;
41 import java.lang.module.ModuleReader;
42 import java.lang.module.ModuleReference;
43 import java.net.URI;
44 import java.net.URL;
45 import java.net.URLConnection;
46 import java.nio.ByteBuffer;
47 import java.nio.file.Files;
48 import java.nio.file.Path;
49 import java.nio.file.Paths;
50 import java.util.Arrays;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Optional;
54 import java.util.Set;
55 import java.util.stream.Collectors;
56 import java.util.spi.ToolProvider;
57 
58 import jdk.internal.module.ModulePath;
59 import jdk.test.lib.compiler.CompilerUtils;
60 import jdk.test.lib.util.JarUtils;
61 
62 import org.testng.annotations.BeforeTest;
63 import org.testng.annotations.Test;
64 import static org.testng.Assert.*;
65 
66 @Test
67 public class ModuleReaderTest {
68 
69     private static final String TEST_SRC = System.getProperty("test.src");
70 
71     private static final Path USER_DIR   = Paths.get(System.getProperty("user.dir"));
72     private static final Path SRC_DIR    = Paths.get(TEST_SRC, "src");
73     private static final Path MODS_DIR   = Paths.get("mods");
74 
75     // the module name of the base module
76     private static final String BASE_MODULE = "java.base";
77 
78     // the module name of the test module
79     private static final String TEST_MODULE = "m";
80 
81     // resources in the base module
82     private static final String[] BASE_RESOURCES = {
83         "java/lang/Object.class"
84     };
85 
86     // (directory) resources that may be in the base module
87     private static final String[] MAYBE_BASE_RESOURCES = {
88         "java",
89         "java/",
90         "java/lang",
91         "java/lang/",
92     };
93 
94     // resource names that should not be found in the base module
95     private static final String[] NOT_BASE_RESOURCES = {
96         "NotFound",
97         "/java",
98         "//java",
99         "/java/lang",
100         "//java/lang",
101         "java//lang",
102         "/java/lang/Object.class",
103         "//java/lang/Object.class",
104         "java/lang/Object.class/",
105         "java//lang//Object.class",
106         "./java/lang/Object.class",
107         "java/./lang/Object.class",
108         "java/lang/./Object.class",
109         "../java/lang/Object.class",
110         "java/../lang/Object.class",
111         "java/lang/../Object.class",
112     };
113 
114     // resources in test module (can't use module-info.class as a test
115     // resource as it will be modified by the jmod tool)
116     private static final String[] TEST_RESOURCES = {
117         "p/Main.class"
118     };
119 
120     // (directory) resources that may be in the test module
121     private static final String[] MAYBE_TEST_RESOURCES = {
122         "p",
123         "p/"
124     };
125 
126     // resource names that should not be found in the test module
127     private static final String[] NOT_TEST_RESOURCES = {
128         "NotFound",
129         "/p",
130         "//p",
131         "/p/Main.class",
132         "//p/Main.class",
133         "p/Main.class/",
134         "p//Main.class",
135         "./p/Main.class",
136         "p/./Main.class",
137         "../p/Main.class",
138         "p/../p/Main.class"
139     };
140 
141 
142     @BeforeTest
compileTestModule()143     public void compileTestModule() throws Exception {
144 
145         // javac -d mods/$TESTMODULE src/$TESTMODULE/**
146         boolean compiled
147             = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
148                                     MODS_DIR.resolve(TEST_MODULE));
149         assertTrue(compiled, "test module did not compile");
150     }
151 
152 
153     /**
154      * Test ModuleReader to module in runtime image
155      */
testImage()156     public void testImage() throws IOException {
157 
158         ModuleFinder finder = ModuleFinder.ofSystem();
159         ModuleReference mref = finder.find(BASE_MODULE).get();
160         ModuleReader reader = mref.open();
161 
162         try (reader) {
163 
164             for (String name : BASE_RESOURCES) {
165                 byte[] expectedBytes;
166                 Module baseModule = Object.class.getModule();
167                 try (InputStream in = baseModule.getResourceAsStream(name)) {
168                     expectedBytes = in.readAllBytes();
169                 }
170 
171                 testFind(reader, name, expectedBytes);
172                 testOpen(reader, name, expectedBytes);
173                 testRead(reader, name, expectedBytes);
174                 testList(reader, name);
175             }
176 
177             // test resources that may be in the base module
178             for (String name : MAYBE_BASE_RESOURCES) {
179                 Optional<URI> ouri = reader.find(name);
180                 ouri.ifPresent(uri -> {
181                     if (name.endsWith("/"))
182                         assertTrue(uri.toString().endsWith("/"));
183                 });
184             }
185 
186             // test "not found" in java.base module
187             for (String name : NOT_BASE_RESOURCES) {
188                 assertFalse(reader.find(name).isPresent());
189                 assertFalse(reader.open(name).isPresent());
190                 assertFalse(reader.read(name).isPresent());
191             }
192 
193             // test nulls
194             try {
195                 reader.find(null);
196                 assertTrue(false);
197             } catch (NullPointerException expected) { }
198 
199             try {
200                 reader.open(null);
201                 assertTrue(false);
202             } catch (NullPointerException expected) { }
203 
204             try {
205                 reader.read(null);
206                 assertTrue(false);
207             } catch (NullPointerException expected) { }
208 
209             try {
210                 reader.release(null);
211                 assertTrue(false);
212             } catch (NullPointerException expected) { }
213 
214         }
215 
216         // test closed ModuleReader
217         try {
218             reader.open(BASE_RESOURCES[0]);
219             assertTrue(false);
220         } catch (IOException expected) { }
221 
222 
223         try {
224             reader.read(BASE_RESOURCES[0]);
225             assertTrue(false);
226         } catch (IOException expected) { }
227     }
228 
229 
230     /**
231      * Test ModuleReader to exploded module
232      */
testExplodedModule()233     public void testExplodedModule() throws IOException {
234         test(MODS_DIR);
235     }
236 
237 
238     /**
239      * Test ModuleReader to modular JAR
240      */
testModularJar()241     public void testModularJar() throws IOException {
242         Path dir = Files.createTempDirectory(USER_DIR, "mlib");
243 
244         // jar cf mlib/${TESTMODULE}.jar -C mods .
245         JarUtils.createJarFile(dir.resolve("m.jar"),
246                                MODS_DIR.resolve(TEST_MODULE));
247 
248         test(dir);
249     }
250 
251 
252     /**
253      * Test ModuleReader to JMOD
254      */
testJMod()255     public void testJMod() throws IOException {
256         Path dir = Files.createTempDirectory(USER_DIR, "mlib");
257 
258         // jmod create --class-path mods/${TESTMODULE}  mlib/${TESTMODULE}.jmod
259         String cp = MODS_DIR.resolve(TEST_MODULE).toString();
260         String jmod = dir.resolve("m.jmod").toString();
261         String[] args = { "create", "--class-path", cp, jmod };
262         ToolProvider jmodTool = ToolProvider.findFirst("jmod")
263             .orElseThrow(() ->
264                 new RuntimeException("jmod tool not found")
265             );
266         assertEquals(jmodTool.run(System.out, System.out, args), 0);
267 
268         test(dir);
269     }
270 
271 
272     /**
273      * The test module is found on the given module path. Open a ModuleReader
274      * to the test module and test the reader.
275      */
test(Path mp)276     void test(Path mp) throws IOException {
277 
278         ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp);
279         ModuleReference mref = finder.find(TEST_MODULE).get();
280         ModuleReader reader = mref.open();
281 
282         try (reader) {
283 
284             // test resources in test module
285             for (String name : TEST_RESOURCES) {
286                 byte[] expectedBytes
287                     = Files.readAllBytes(MODS_DIR
288                         .resolve(TEST_MODULE)
289                         .resolve(name.replace('/', File.separatorChar)));
290 
291                 testFind(reader, name, expectedBytes);
292                 testOpen(reader, name, expectedBytes);
293                 testRead(reader, name, expectedBytes);
294                 testList(reader, name);
295             }
296 
297             // test resources that may be in the test module
298             for (String name : MAYBE_TEST_RESOURCES) {
299                 System.out.println(name);
300                 Optional<URI> ouri = reader.find(name);
301                 ouri.ifPresent(uri -> {
302                     if (name.endsWith("/"))
303                         assertTrue(uri.toString().endsWith("/"));
304                 });
305             }
306 
307             // test "not found" in test module
308             for (String name : NOT_TEST_RESOURCES) {
309                 assertFalse(reader.find(name).isPresent());
310                 assertFalse(reader.open(name).isPresent());
311                 assertFalse(reader.read(name).isPresent());
312             }
313 
314             // test nulls
315             try {
316                 reader.find(null);
317                 assertTrue(false);
318             } catch (NullPointerException expected) { }
319 
320             try {
321                 reader.open(null);
322                 assertTrue(false);
323             } catch (NullPointerException expected) { }
324 
325             try {
326                 reader.read(null);
327                 assertTrue(false);
328             } catch (NullPointerException expected) { }
329 
330             try {
331                 reader.release(null);
332                 throw new RuntimeException();
333             } catch (NullPointerException expected) { }
334 
335         }
336 
337         // test closed ModuleReader
338         try {
339             reader.open(TEST_RESOURCES[0]);
340             assertTrue(false);
341         } catch (IOException expected) { }
342 
343 
344         try {
345             reader.read(TEST_RESOURCES[0]);
346             assertTrue(false);
347         } catch (IOException expected) { }
348 
349         try {
350             reader.list();
351             assertTrue(false);
352         } catch (IOException expected) { }
353     }
354 
355     /**
356      * Test ModuleReader#find
357      */
testFind(ModuleReader reader, String name, byte[] expectedBytes)358     void testFind(ModuleReader reader, String name, byte[] expectedBytes)
359         throws IOException
360     {
361         Optional<URI> ouri = reader.find(name);
362         assertTrue(ouri.isPresent());
363 
364         URL url = ouri.get().toURL();
365         if (!url.getProtocol().equalsIgnoreCase("jmod")) {
366             URLConnection uc = url.openConnection();
367             uc.setUseCaches(false);
368             try (InputStream in = uc.getInputStream()) {
369                 byte[] bytes = in.readAllBytes();
370                 assertTrue(Arrays.equals(bytes, expectedBytes));
371             }
372         }
373     }
374 
375     /**
376      * Test ModuleReader#open
377      */
testOpen(ModuleReader reader, String name, byte[] expectedBytes)378     void testOpen(ModuleReader reader, String name, byte[] expectedBytes)
379         throws IOException
380     {
381         Optional<InputStream> oin = reader.open(name);
382         assertTrue(oin.isPresent());
383 
384         InputStream in = oin.get();
385         try (in) {
386             byte[] bytes = in.readAllBytes();
387             assertTrue(Arrays.equals(bytes, expectedBytes));
388         }
389     }
390 
391     /**
392      * Test ModuleReader#read
393      */
testRead(ModuleReader reader, String name, byte[] expectedBytes)394     void testRead(ModuleReader reader, String name, byte[] expectedBytes)
395         throws IOException
396     {
397         Optional<ByteBuffer> obb = reader.read(name);
398         assertTrue(obb.isPresent());
399 
400         ByteBuffer bb = obb.get();
401         try {
402             int rem = bb.remaining();
403             assertTrue(rem == expectedBytes.length);
404             byte[] bytes = new byte[rem];
405             bb.get(bytes);
406             assertTrue(Arrays.equals(bytes, expectedBytes));
407         } finally {
408             reader.release(bb);
409         }
410     }
411 
412     /**
413      * Test ModuleReader#list
414      */
testList(ModuleReader reader, String name)415     void testList(ModuleReader reader, String name) throws IOException {
416         List<String> list = reader.list().collect(Collectors.toList());
417         Set<String> names = new HashSet<>(list);
418         assertTrue(names.size() == list.size()); // no duplicates
419 
420         assertTrue(names.contains("module-info.class"));
421         assertTrue(names.contains(name));
422 
423         // all resources should be locatable via find
424         for (String e : names) {
425             assertTrue(reader.find(e).isPresent());
426         }
427     }
428 
429 }
430