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