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 jdk.compiler
28  * @build LayerAndLoadersTest
29  *        jdk.test.lib.compiler.CompilerUtils
30  *        jdk.test.lib.util.ModuleUtils
31  * @run testng LayerAndLoadersTest
32  * @summary Tests for java.lang.ModuleLayer@defineModulesWithXXX methods
33  */
34 
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.UncheckedIOException;
38 import java.lang.module.Configuration;
39 import java.lang.module.ModuleDescriptor;
40 import java.lang.module.ModuleFinder;
41 import java.lang.module.ModuleReference;
42 import java.lang.module.ResolvedModule;
43 import java.lang.reflect.Method;
44 import java.net.URL;
45 import java.nio.file.Path;
46 import java.nio.file.Paths;
47 import java.util.ArrayList;
48 import java.util.Enumeration;
49 import java.util.HashMap;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Optional;
54 import java.util.ServiceLoader;
55 import java.util.Set;
56 import java.util.stream.Collectors;
57 
58 import jdk.test.lib.compiler.CompilerUtils;
59 import jdk.test.lib.util.ModuleUtils;
60 
61 import org.testng.annotations.BeforeTest;
62 import org.testng.annotations.Test;
63 import static org.testng.Assert.*;
64 
65 @Test
66 public class LayerAndLoadersTest {
67 
68     private static final String TEST_SRC = System.getProperty("test.src");
69 
70     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
71     private static final Path MODS_DIR = Paths.get("mods");
72 
73     @BeforeTest
setup()74     public void setup() throws Exception {
75         // javac -d mods --module-source-path src src/**
76         assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR,
77                 "--module-source-path", SRC_DIR.toString()));
78     }
79 
80 
81     /**
82      * Basic test of ModuleLayer.defineModulesWithOneLoader
83      *
84      * Test scenario:
85      * m1 requires m2 and m3
86      */
testWithOneLoader()87     public void testWithOneLoader() throws Exception {
88         Configuration cf = resolve("m1");
89 
90         ClassLoader scl = ClassLoader.getSystemClassLoader();
91 
92         ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl);
93 
94         checkLayer(layer, "m1", "m2", "m3");
95 
96         ClassLoader cl1 = layer.findLoader("m1");
97         ClassLoader cl2 = layer.findLoader("m2");
98         ClassLoader cl3 = layer.findLoader("m3");
99 
100         assertTrue(cl1.getParent() == scl);
101         assertTrue(cl2 == cl1);
102         assertTrue(cl3 == cl1);
103 
104         invoke(layer, "m1", "p.Main");
105     }
106 
107 
108     /**
109      * Basic test of ModuleLayer.defineModulesWithManyLoaders
110      *
111      * Test scenario:
112      * m1 requires m2 and m3
113      */
testWithManyLoaders()114     public void testWithManyLoaders() throws Exception {
115         Configuration cf = resolve("m1");
116 
117         ClassLoader scl = ClassLoader.getSystemClassLoader();
118 
119         ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl);
120 
121         checkLayer(layer, "m1", "m2", "m3");
122 
123         ClassLoader cl1 = layer.findLoader("m1");
124         ClassLoader cl2 = layer.findLoader("m2");
125         ClassLoader cl3 = layer.findLoader("m3");
126 
127         assertTrue(cl1.getParent() == scl);
128         assertTrue(cl2.getParent() == scl);
129         assertTrue(cl3.getParent() == scl);
130         assertTrue(cl2 != cl1);
131         assertTrue(cl3 != cl1);
132         assertTrue(cl3 != cl2);
133 
134         invoke(layer, "m1", "p.Main");
135     }
136 
137 
138     /**
139      * Basic test of ModuleLayer.defineModulesWithOneLoader where one of the
140      * modules is a service provider module.
141      *
142      * Test scenario:
143      * m1 requires m2 and m3
144      * m1 uses S
145      * m4 provides S with ...
146      */
testServicesWithOneLoader()147     public void testServicesWithOneLoader() throws Exception {
148         Configuration cf = resolveAndBind("m1");
149 
150         ClassLoader scl = ClassLoader.getSystemClassLoader();
151 
152         ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl);
153 
154         checkLayer(layer, "m1", "m2", "m3", "m4");
155 
156         ClassLoader cl1 = layer.findLoader("m1");
157         ClassLoader cl2 = layer.findLoader("m2");
158         ClassLoader cl3 = layer.findLoader("m3");
159         ClassLoader cl4 = layer.findLoader("m4");
160 
161         assertTrue(cl1.getParent() == scl);
162         assertTrue(cl2 == cl1);
163         assertTrue(cl3 == cl1);
164         assertTrue(cl4 == cl1);
165 
166         Class<?> serviceType = cl1.loadClass("p.Service");
167         assertTrue(serviceType.getClassLoader() == cl1);
168 
169         Iterator<?> iter = ServiceLoader.load(serviceType, cl1).iterator();
170         Object provider = iter.next();
171         assertTrue(serviceType.isInstance(provider));
172         assertTrue(provider.getClass().getClassLoader() == cl1);
173         assertFalse(iter.hasNext());
174     }
175 
176 
177     /**
178      * Basic test of ModuleLayer.defineModulesWithManyLoaders where one of the
179      * modules is a service provider module.
180      *
181      * Test scenario:
182      * m1 requires m2 and m3
183      * m1 uses S
184      * m4 provides S with ...
185      */
testServicesWithManyLoaders()186     public void testServicesWithManyLoaders() throws Exception {
187         Configuration cf = resolveAndBind("m1");
188 
189         ClassLoader scl = ClassLoader.getSystemClassLoader();
190 
191         ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl);
192 
193         checkLayer(layer, "m1", "m2", "m3", "m4");
194 
195         ClassLoader cl1 = layer.findLoader("m1");
196         ClassLoader cl2 = layer.findLoader("m2");
197         ClassLoader cl3 = layer.findLoader("m3");
198         ClassLoader cl4 = layer.findLoader("m4");
199 
200         assertTrue(cl1.getParent() == scl);
201         assertTrue(cl2.getParent() == scl);
202         assertTrue(cl3.getParent() == scl);
203         assertTrue(cl4.getParent() == scl);
204         assertTrue(cl2 != cl1);
205         assertTrue(cl3 != cl1);
206         assertTrue(cl3 != cl2);
207         assertTrue(cl4 != cl1);
208         assertTrue(cl4 != cl2);
209         assertTrue(cl4 != cl3);
210 
211         Class<?> serviceType = cl1.loadClass("p.Service");
212         assertTrue(serviceType.getClassLoader() == cl1);
213 
214         // Test that the service provider can be located via any of
215         // the class loaders in the layer
216         for (Module m : layer.modules()) {
217             ClassLoader loader = m.getClassLoader();
218             Iterator<?> iter = ServiceLoader.load(serviceType, loader).iterator();
219             Object provider = iter.next();
220             assertTrue(serviceType.isInstance(provider));
221             assertTrue(provider.getClass().getClassLoader() == cl4);
222             assertFalse(iter.hasNext());
223         }
224     }
225 
226 
227     /**
228      * Tests that the class loaders created by defineModulesWithXXX delegate
229      * to the given parent class loader.
230      */
testDelegationToParent()231     public void testDelegationToParent() throws Exception {
232         Configuration cf = resolve("m1");
233 
234         ClassLoader parent = this.getClass().getClassLoader();
235         String cn = this.getClass().getName();
236 
237         // one loader
238         ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, parent);
239         testLoad(layer, cn);
240 
241         // one loader with boot loader as parent
242         layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, null);
243         testLoadFail(layer, cn);
244 
245         // many loaders
246         layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, parent);
247         testLoad(layer, cn);
248 
249         // many loader with boot loader as parent
250         layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, null);
251         testLoadFail(layer, cn);
252     }
253 
254 
255     /**
256      * Test defineModulesWithXXX when modules that have overlapping packages.
257      *
258      * Test scenario:
259      * m1 exports p
260      * m2 exports p
261      */
testOverlappingPackages()262     public void testOverlappingPackages() {
263         ModuleDescriptor descriptor1
264                 = ModuleDescriptor.newModule("m1").exports("p").build();
265 
266         ModuleDescriptor descriptor2
267                 = ModuleDescriptor.newModule("m2").exports("p").build();
268 
269         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
270 
271         Configuration cf = ModuleLayer.boot()
272                 .configuration()
273                 .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2"));
274 
275         // cannot define both module m1 and m2 to the same class loader
276         try {
277             ModuleLayer.boot().defineModulesWithOneLoader(cf, null);
278             assertTrue(false);
279         } catch (LayerInstantiationException expected) { }
280 
281         // should be okay to have one module per class loader
282         ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, null);
283         checkLayer(layer, "m1", "m2");
284     }
285 
286 
287     /**
288      * Test ModuleLayer.defineModulesWithXXX with split delegation.
289      *
290      * Test scenario:
291      * layer1: m1 exports p, m2 exports p
292      * layer2: m3 reads m1, m4 reads m2
293      */
testSplitDelegation()294     public void testSplitDelegation() {
295         ModuleDescriptor descriptor1
296                 = ModuleDescriptor.newModule("m1").exports("p").build();
297 
298         ModuleDescriptor descriptor2
299                 = ModuleDescriptor.newModule("m2").exports("p").build();
300 
301         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
302 
303         Configuration cf1 = ModuleLayer.boot()
304                 .configuration()
305                 .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2"));
306 
307         ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null);
308         checkLayer(layer1, "m1", "m2");
309 
310         ModuleDescriptor descriptor3
311                 = ModuleDescriptor.newModule("m3").requires("m1").build();
312 
313         ModuleDescriptor descriptor4
314                 = ModuleDescriptor.newModule("m4").requires("m2").build();
315 
316         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
317 
318         Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(),
319                 Set.of("m3", "m4"));
320 
321         // package p cannot be supplied by two class loaders
322         try {
323             layer1.defineModulesWithOneLoader(cf2, null);
324             assertTrue(false);
325         } catch (LayerInstantiationException expected) { }
326 
327         // no split delegation when modules have their own class loader
328         ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
329         checkLayer(layer2, "m3", "m4");
330     }
331 
332 
333     /**
334      * Test ModuleLayer.defineModulesWithXXX when the modules that override same
335      * named modules in the parent layer.
336      *
337      * Test scenario:
338      * layer1: m1, m2, m3 => same loader
339      * layer2: m1, m2, m4 => same loader
340      */
testOverriding1()341     public void testOverriding1() throws Exception {
342         Configuration cf1 = resolve("m1");
343 
344         ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithOneLoader(cf1, null);
345         checkLayer(layer1, "m1", "m2", "m3");
346 
347         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
348         Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(),
349                 Set.of("m1"));
350 
351         ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null);
352         checkLayer(layer2, "m1", "m2", "m3");
353         invoke(layer1, "m1", "p.Main");
354 
355         ClassLoader loader1 = layer1.findLoader("m1");
356         ClassLoader loader2 = layer1.findLoader("m2");
357         ClassLoader loader3 = layer1.findLoader("m3");
358 
359         ClassLoader loader4 = layer2.findLoader("m1");
360         ClassLoader loader5 = layer2.findLoader("m2");
361         ClassLoader loader6 = layer2.findLoader("m3");
362 
363         assertTrue(loader1 == loader2);
364         assertTrue(loader1 == loader3);
365 
366         assertTrue(loader4 == loader5);
367         assertTrue(loader4 == loader6);
368         assertTrue(loader4 != loader1);
369 
370         assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
371         assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
372         assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1);
373 
374         assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
375         assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4);
376         assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader4);
377     }
378 
379 
380     /**
381      * Test Layer defineModulesWithXXX when the modules that override same
382      * named modules in the parent layer.
383      *
384      * Test scenario:
385      * layer1: m1, m2, m3 => loader pool
386      * layer2: m1, m2, m3 => loader pool
387      */
testOverriding2()388     public void testOverriding2() throws Exception {
389         Configuration cf1 = resolve("m1");
390 
391         ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null);
392         checkLayer(layer1, "m1", "m2", "m3");
393 
394         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
395         Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(),
396                 Set.of("m1"));
397 
398         ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
399         checkLayer(layer2, "m1", "m2", "m3");
400         invoke(layer1, "m1", "p.Main");
401 
402         ClassLoader loader1 = layer1.findLoader("m1");
403         ClassLoader loader2 = layer1.findLoader("m2");
404         ClassLoader loader3 = layer1.findLoader("m3");
405 
406         ClassLoader loader4 = layer2.findLoader("m1");
407         ClassLoader loader5 = layer2.findLoader("m2");
408         ClassLoader loader6 = layer2.findLoader("m3");
409 
410         assertTrue(loader4 != loader1);
411         assertTrue(loader5 != loader2);
412         assertTrue(loader6 != loader3);
413 
414         assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
415         assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2);
416         assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3);
417 
418         // p.Main is not visible via loader2
419         try {
420             loader2.loadClass("p.Main");
421             assertTrue(false);
422         } catch (ClassNotFoundException expected) { }
423 
424         // w.Hello is not visible via loader2
425         try {
426             loader2.loadClass("w.Hello");
427             assertTrue(false);
428         } catch (ClassNotFoundException expected) { }
429 
430         // p.Main is not visible via loader3
431         try {
432             loader3.loadClass("p.Main");
433             assertTrue(false);
434         } catch (ClassNotFoundException expected) { }
435 
436         // q.Hello is not visible via loader3
437         try {
438             loader3.loadClass("q.Hello");
439             assertTrue(false);
440         } catch (ClassNotFoundException expected) { }
441 
442 
443         assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
444         assertTrue(loader5.loadClass("q.Hello").getClassLoader() == loader5);
445         assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6);
446 
447         // p.Main is not visible via loader5
448         try {
449             loader5.loadClass("p.Main");
450             assertTrue(false);
451         } catch (ClassNotFoundException expected) { }
452 
453         // w.Hello is not visible via loader5
454         try {
455             loader5.loadClass("w.Hello");
456             assertTrue(false);
457         } catch (ClassNotFoundException expected) { }
458 
459         // p.Main is not visible via loader6
460         try {
461             loader6.loadClass("p.Main");
462             assertTrue(false);
463         } catch (ClassNotFoundException expected) { }
464 
465         // q.Hello is not visible via loader6
466         try {
467             loader6.loadClass("q.Hello");
468             assertTrue(false);
469         } catch (ClassNotFoundException expected) { }
470     }
471 
472 
473     /**
474      * Test ModuleLayer.defineModulesWithXXX when the modules that override same
475      * named modules in the parent layer.
476      *
477      * layer1: m1, m2, m3 => same loader
478      * layer2: m1, m3 => same loader
479      */
testOverriding3()480     public void testOverriding3() throws Exception {
481         Configuration cf1 = resolve("m1");
482 
483         ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithOneLoader(cf1, null);
484         checkLayer(layer1, "m1", "m2", "m3");
485 
486         ModuleFinder finder = finderFor("m1", "m3");
487 
488         Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(),
489                 Set.of("m1"));
490 
491         ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null);
492         checkLayer(layer2, "m1", "m3");
493         invoke(layer1, "m1", "p.Main");
494 
495         ClassLoader loader1 = layer1.findLoader("m1");
496         ClassLoader loader2 = layer2.findLoader("m1");
497 
498         assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
499         assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
500         assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1);
501 
502         assertTrue(loader2.loadClass("p.Main").getClassLoader() == loader2);
503         assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader1);
504         assertTrue(loader2.loadClass("w.Hello").getClassLoader() == loader2);
505     }
506 
507 
508     /**
509      * Test Layer defineModulesWithXXX when the modules that override same
510      * named modules in the parent layer.
511      *
512      * layer1: m1, m2, m3 => loader pool
513      * layer2: m1, m3 => loader pool
514      */
testOverriding4()515     public void testOverriding4() throws Exception {
516         Configuration cf1 = resolve("m1");
517 
518         ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null);
519         checkLayer(layer1, "m1", "m2", "m3");
520 
521         ModuleFinder finder = finderFor("m1", "m3");
522 
523         Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(),
524                 Set.of("m1"));
525 
526         ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null);
527         checkLayer(layer2, "m1", "m3");
528         invoke(layer1, "m1", "p.Main");
529 
530         ClassLoader loader1 = layer1.findLoader("m1");
531         ClassLoader loader2 = layer1.findLoader("m2");
532         ClassLoader loader3 = layer1.findLoader("m3");
533 
534         ClassLoader loader4 = layer2.findLoader("m1");
535         ClassLoader loader5 = layer2.findLoader("m2");
536         ClassLoader loader6 = layer2.findLoader("m3");
537 
538         assertTrue(loader4 != loader1);
539         assertTrue(loader5 == loader2);  // m2 not overridden
540         assertTrue(loader6 != loader3);
541 
542         assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
543         assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2);
544         assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3);
545 
546         assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2);
547 
548         assertTrue(loader3.loadClass("w.Hello").getClassLoader() == loader3);
549 
550         assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4);
551         assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader2);
552         assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader6);
553 
554         assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6);
555     }
556 
557     /**
558      * Basic test for locating resources with a class loader created by
559      * defineModulesWithOneLoader.
560      */
testResourcesWithOneLoader()561     public void testResourcesWithOneLoader() throws Exception {
562         testResourcesWithOneLoader(ClassLoader.getSystemClassLoader());
563         testResourcesWithOneLoader(null);
564     }
565 
566     /**
567      * Test locating resources with the class loader created by
568      * defineModulesWithOneLoader. The class loader has the given class
569      * loader as its parent.
570      */
testResourcesWithOneLoader(ClassLoader parent)571     void testResourcesWithOneLoader(ClassLoader parent) throws Exception {
572         Configuration cf = resolve("m1");
573         ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, parent);
574 
575         ClassLoader loader = layer.findLoader("m1");
576         assertNotNull(loader);
577         assertTrue(loader.getParent() == parent);
578 
579         // check that getResource and getResources are consistent
580         URL url1 = loader.getResource("module-info.class");
581         URL url2 = loader.getResources("module-info.class").nextElement();
582         assertEquals(url1.toURI(), url2.toURI());
583 
584         // use getResources to find module-info.class resources
585         Enumeration<URL> urls = loader.getResources("module-info.class");
586         List<String> list = readModuleNames(urls);
587 
588         // m1, m2, ... should be first (order not specified)
589         int count = cf.modules().size();
590         cf.modules().stream()
591                 .map(ResolvedModule::name)
592                 .forEach(mn -> assertTrue(list.indexOf(mn) < count));
593 
594         // java.base should be after m1, m2, ...
595         assertTrue(list.indexOf("java.base") >= count);
596 
597         // check resources(String)
598         List<String> list2 = loader.resources("module-info.class")
599                 .map(this::readModuleName)
600                 .collect(Collectors.toList());
601         assertEquals(list2, list);
602 
603         // check nulls
604         try {
605             loader.getResource(null);
606             assertTrue(false);
607         } catch (NullPointerException e) { }
608         try {
609             loader.getResources(null);
610             assertTrue(false);
611         } catch (NullPointerException e) { }
612         try {
613             loader.resources(null);
614             assertTrue(false);
615         } catch (NullPointerException e) { }
616     }
617 
618     /**
619      * Basic test for locating resources with class loaders created by
620      * defineModulesWithManyLoaders.
621      */
testResourcesWithManyLoaders()622     public void testResourcesWithManyLoaders() throws Exception {
623         testResourcesWithManyLoaders(ClassLoader.getSystemClassLoader());
624         testResourcesWithManyLoaders(null);
625     }
626 
627     /**
628      * Test locating resources with class loaders created by
629      * defineModulesWithManyLoaders. The class loaders have the given class
630      * loader as their parent.
631      */
testResourcesWithManyLoaders(ClassLoader parent)632     void testResourcesWithManyLoaders(ClassLoader parent) throws Exception {
633         Configuration cf = resolve("m1");
634         ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, parent);
635 
636         for (Module m : layer.modules()) {
637             String name = m.getName();
638             ClassLoader loader = m.getClassLoader();
639             assertNotNull(loader);
640             assertTrue(loader.getParent() == parent);
641 
642             // getResource should find the module-info.class for the module
643             URL url = loader.getResource("module-info.class");
644             assertEquals(readModuleName(url), name);
645 
646             // list of modules names read from module-info.class
647             Enumeration<URL> urls = loader.getResources("module-info.class");
648             List<String> list = readModuleNames(urls);
649 
650             // module should be the first element
651             assertTrue(list.indexOf(name) == 0);
652 
653             // the module-info.class for the other modules in the layer
654             // should not be found
655             layer.modules().stream()
656                     .map(Module::getName)
657                     .filter(mn -> !mn.equals(name))
658                     .forEach(mn -> assertTrue(list.indexOf(mn) < 0));
659 
660             // java.base cannot be the first element
661             assertTrue(list.indexOf("java.base") > 0);
662 
663             // check resources(String)
664             List<String> list2 = loader.resources("module-info.class")
665                     .map(this::readModuleName)
666                     .collect(Collectors.toList());
667             assertEquals(list2, list);
668 
669             // check nulls
670             try {
671                 loader.getResource(null);
672                 assertTrue(false);
673             } catch (NullPointerException e) { }
674             try {
675                 loader.getResources(null);
676                 assertTrue(false);
677             } catch (NullPointerException e) { }
678             try {
679                 loader.resources(null);
680                 assertTrue(false);
681             } catch (NullPointerException e) { }
682         }
683     }
684 
readModuleNames(Enumeration<URL> e)685     private List<String> readModuleNames(Enumeration<URL> e) {
686         List<String> list = new ArrayList<>();
687         while (e.hasMoreElements()) {
688             URL url = e.nextElement();
689             list.add(readModuleName(url));
690         }
691         return list;
692     }
693 
readModuleName(URL url)694     private String readModuleName(URL url) {
695         try (InputStream in = url.openStream()) {
696             ModuleDescriptor descriptor = ModuleDescriptor.read(in);
697             return descriptor.name();
698         } catch (IOException ioe) {
699             throw new UncheckedIOException(ioe);
700         }
701     }
702 
703 
704     // -- supporting methods --
705 
706 
707     /**
708      * Resolve the given modules, by name, and returns the resulting
709      * Configuration.
710      */
resolve(String... roots)711     private static Configuration resolve(String... roots) {
712         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
713         return ModuleLayer.boot()
714             .configuration()
715             .resolve(finder, ModuleFinder.of(), Set.of(roots));
716     }
717 
718     /**
719      * Resolve the given modules, by name, and returns the resulting
720      * Configuration.
721      */
resolveAndBind(String... roots)722     private static Configuration resolveAndBind(String... roots) {
723         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
724         return ModuleLayer.boot()
725             .configuration()
726             .resolveAndBind(finder, ModuleFinder.of(), Set.of(roots));
727     }
728 
729 
730     /**
731      * Invokes the static void main(String[]) method on the given class
732      * in the given module.
733      */
invoke(ModuleLayer layer, String mn, String mc)734     private static void invoke(ModuleLayer layer, String mn, String mc) throws Exception {
735         ClassLoader loader = layer.findLoader(mn);
736         Class<?> c = loader.loadClass(mc);
737         Method mainMethod = c.getMethod("main", String[].class);
738         mainMethod.invoke(null, (Object)new String[0]);
739     }
740 
741 
742     /**
743      * Checks that the given layer contains exactly the expected modules
744      * (by name).
745      */
checkLayer(ModuleLayer layer, String ... expected)746     private void checkLayer(ModuleLayer layer, String ... expected) {
747         Set<String> names = layer.modules().stream()
748                 .map(Module::getName)
749                 .collect(Collectors.toSet());
750         assertTrue(names.size() == expected.length);
751         for (String name : expected) {
752             assertTrue(names.contains(name));
753         }
754     }
755 
756 
757     /**
758      * Test that a class can be loaded via the class loader of all modules
759      * in the given layer.
760      */
testLoad(ModuleLayer layer, String cn)761     static void testLoad(ModuleLayer layer, String cn) throws Exception {
762         for (Module m : layer.modules()) {
763             ClassLoader l = m.getClassLoader();
764             l.loadClass(cn);
765         }
766     }
767 
768 
769     /**
770      * Test that a class cannot be loaded via any of the class loaders of
771      * the modules in the given layer.
772      */
testLoadFail(ModuleLayer layer, String cn)773     static void testLoadFail(ModuleLayer layer, String cn) throws Exception {
774         for (Module m : layer.modules()) {
775             ClassLoader l = m.getClassLoader();
776             try {
777                 l.loadClass(cn);
778                 assertTrue(false);
779             } catch (ClassNotFoundException expected) { }
780         }
781     }
782 
783 
784     /**
785      * Returns a ModuleFinder that only finds the given test modules
786      */
finderFor(String... names)787     static ModuleFinder finderFor(String... names) {
788 
789         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
790 
791         Map<String, ModuleReference> mrefs = new HashMap<>();
792         for (String name : names) {
793             Optional<ModuleReference> omref = finder.find(name);
794             assert omref.isPresent();
795             mrefs.put(name, omref.get());
796         }
797 
798         return new ModuleFinder() {
799             @Override
800             public Optional<ModuleReference> find(String name) {
801                 ModuleReference mref = mrefs.get(name);
802                 return Optional.ofNullable(mref);
803             }
804             @Override
805             public Set<ModuleReference> findAll() {
806                 return mrefs.values().stream().collect(Collectors.toSet());
807             }
808         };
809     }
810 
811 }
812