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