1 /*
   2  * Copyright (c) 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  * @modules jdk.zipfs
  27  * @library /lib/testlibrary
  28  * @build ModulesInCustomFileSystem JarUtils m1/* m2/*
  29  * @run testng/othervm ModulesInCustomFileSystem
  30  * @summary Test ModuleFinder to find modules in a custom file system
  31  */
  32 
  33 import java.io.File;
  34 import java.lang.module.Configuration;
  35 import java.lang.module.ModuleFinder;
  36 import java.lang.module.ModuleReader;
  37 import java.lang.module.ModuleReference;
  38 import java.lang.reflect.Method;
  39 import java.nio.file.FileSystem;
  40 import java.nio.file.FileSystems;
  41 import java.nio.file.Files;
  42 import java.nio.file.Path;
  43 import java.nio.file.Paths;
  44 import java.util.Set;
  45 
  46 import org.testng.annotations.Test;
  47 import static org.testng.Assert.*;
  48 
  49 @Test
  50 public class ModulesInCustomFileSystem {
  51     private static final Path HERE = Paths.get("");
  52 
  53     /**
  54      * Test exploded modules in a JAR file system.
  55      */
  56     public void testExplodedModulesInJarFileSystem() throws Exception {
  57         Path m1 = findModuleDirectory("m1");
  58         Path m2 = findModuleDirectory("m2");
  59         Path mlib = m1.getParent();
  60         assertEquals(mlib, m2.getParent());
  61 
  62         // create JAR file containing m1/** and m2/**
  63         Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
  64         JarUtils.createJarFile(jar, mlib);
  65         testJarFileSystem(jar);
  66     }
  67 
  68     /**
  69      * Test modular JARs in a JAR file system
  70      */
  71     public void testModularJARsInJarFileSystem() throws Exception {
  72         Path m1 = findModuleDirectory("m1");
  73         Path m2 = findModuleDirectory("m2");
  74         Path contents = Files.createTempDirectory(HERE, "contents");
  75         JarUtils.createJarFile(contents.resolve("m1.jar"), m1);
  76         JarUtils.createJarFile(contents.resolve("m2.jar"), m2);
  77 
  78         // create JAR file containing m1.jar and m2.jar
  79         Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
  80         JarUtils.createJarFile(jar, contents);
  81         testJarFileSystem(jar);
  82     }
  83 
  84     /**
  85      * Opens a JAR file as a file system
  86      */
  87     private void testJarFileSystem(Path jar) throws Exception {
  88         ClassLoader scl = ClassLoader.getSystemClassLoader();
  89         try (FileSystem fs = FileSystems.newFileSystem(jar, scl)) {
  90             // ModuleFinder to find modules in top-level directory
  91             Path top = fs.getPath("/");
  92             ModuleFinder finder = ModuleFinder.of(top);
  93 
  94             // list the modules
  95             listAllModules(finder);
  96 
  97             // load modules into child layer, invoking m1/p.Main
  98             loadAndRunModule(finder);
  99         }
 100     }
 101 
 102     /**
 103      * List all modules that the finder finds and the resources in the module.
 104      */
 105     private void listAllModules(ModuleFinder finder) throws Exception {
 106         for (ModuleReference mref : finder.findAll()) {
 107             System.out.println(mref.descriptor());
 108             try (ModuleReader reader = mref.open()) {
 109                 reader.list().forEach(name -> System.out.format("  %s%n", name));
 110             }
 111         }
 112     }
 113 
 114     /**
 115      * Creates a child layer with m1 and m2, invokes m1/p.Main to ensure that
 116      * classes can be loaded.
 117      */
 118     private void loadAndRunModule(ModuleFinder finder) throws Exception {
 119         ModuleLayer bootLayer = ModuleLayer.boot();
 120         Configuration cf = bootLayer.configuration()
 121                 .resolve(finder, ModuleFinder.of(), Set.of("m1"));
 122         ClassLoader scl = ClassLoader.getSystemClassLoader();
 123         ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
 124         Class<?> c = layer.findLoader("m1").loadClass("p.Main");
 125         Method m = c.getMethod("main", String[].class);
 126         m.invoke(null, (Object)new String[0]);
 127     }
 128 
 129     /**
 130      * Find the directory for a module on the module path
 131      */
 132     private Path findModuleDirectory(String name) {
 133         String mp = System.getProperty("jdk.module.path");
 134         for (String element : mp.split(File.pathSeparator)) {
 135             Path dir = Paths.get(element).resolve(name);
 136             if (Files.exists(dir)) {
 137                 return dir;
 138             }
 139         }
 140         assertFalse(true);
 141         return null;
 142     }
 143 }