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.misc
  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.misc.SharedSecrets;
  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     // resources in test module (can't use module-info.class as a test
  83     // resource as it will be modified by the jmod tool)
  84     private static final String[] TEST_RESOURCES = {
  85         "p/Main.class"
  86     };
  87 
  88     // a resource that is not in the base or test module
  89     private static final String NOT_A_RESOURCE = "NotAResource";
  90 
  91 
  92     @BeforeTest
  93     public void compileTestModule() throws Exception {
  94 
  95         // javac -d mods/$TESTMODULE src/$TESTMODULE/**
  96         boolean compiled
  97             = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
  98                                     MODS_DIR.resolve(TEST_MODULE));
  99         assertTrue(compiled, "test module did not compile");
 100     }
 101 
 102 
 103     /**
 104      * Test ModuleReader to module in runtime image
 105      */
 106     public void testImage() throws IOException {
 107 
 108         ModuleFinder finder = ModuleFinder.ofSystem();
 109         ModuleReference mref = finder.find(BASE_MODULE).get();
 110         ModuleReader reader = mref.open();
 111 
 112         try (reader) {
 113 
 114             for (String name : BASE_RESOURCES) {
 115                 byte[] expectedBytes;
 116                 Module baseModule = Object.class.getModule();
 117                 try (InputStream in = baseModule.getResourceAsStream(name)) {
 118                     expectedBytes = in.readAllBytes();
 119                 }
 120 
 121                 testFind(reader, name, expectedBytes);
 122                 testOpen(reader, name, expectedBytes);
 123                 testRead(reader, name, expectedBytes);
 124                 testList(reader, name);
 125 
 126             }
 127 
 128             // test "not found"
 129             assertFalse(reader.find(NOT_A_RESOURCE).isPresent());
 130             assertFalse(reader.open(NOT_A_RESOURCE).isPresent());
 131             assertFalse(reader.read(NOT_A_RESOURCE).isPresent());
 132 
 133 
 134             // test nulls
 135             try {
 136                 reader.find(null);
 137                 assertTrue(false);
 138             } catch (NullPointerException expected) { }
 139 
 140             try {
 141                 reader.open(null);
 142                 assertTrue(false);
 143             } catch (NullPointerException expected) { }
 144 
 145             try {
 146                 reader.read(null);
 147                 assertTrue(false);
 148             } catch (NullPointerException expected) { }
 149 
 150             try {
 151                 reader.release(null);
 152                 assertTrue(false);
 153             } catch (NullPointerException expected) { }
 154 
 155         }
 156 
 157         // test closed ModuleReader
 158         try {
 159             reader.open(BASE_RESOURCES[0]);
 160             assertTrue(false);
 161         } catch (IOException expected) { }
 162 
 163 
 164         try {
 165             reader.read(BASE_RESOURCES[0]);
 166             assertTrue(false);
 167         } catch (IOException expected) { }
 168     }
 169 
 170 
 171     /**
 172      * Test ModuleReader to exploded module
 173      */
 174     public void testExplodedModule() throws IOException {
 175         test(MODS_DIR);
 176     }
 177 
 178 
 179     /**
 180      * Test ModuleReader to modular JAR
 181      */
 182     public void testModularJar() throws IOException {
 183         Path dir = Files.createTempDirectory(USER_DIR, "mlib");
 184 
 185         // jar cf mlib/${TESTMODULE}.jar -C mods .
 186         JarUtils.createJarFile(dir.resolve("m.jar"),
 187                                MODS_DIR.resolve(TEST_MODULE));
 188 
 189         test(dir);
 190     }
 191 
 192 
 193     /**
 194      * Test ModuleReader to JMOD
 195      */
 196     public void testJMod() throws IOException {
 197         Path dir = Files.createTempDirectory(USER_DIR, "mlib");
 198 
 199         // jmod create --class-path mods/${TESTMODULE}  mlib/${TESTMODULE}.jmod
 200         String cp = MODS_DIR.resolve(TEST_MODULE).toString();
 201         String jmod = dir.resolve("m.jmod").toString();
 202         String[] args = { "create", "--class-path", cp, jmod };
 203         ToolProvider jmodTool = ToolProvider.findFirst("jmod")
 204             .orElseThrow(() ->
 205                 new RuntimeException("jmod tool not found")
 206             );
 207         assertEquals(jmodTool.run(System.out, System.out, args), 0);
 208 
 209         test(dir);
 210     }
 211 
 212 
 213     /**
 214      * The test module is found on the given module path. Open a ModuleReader
 215      * to the test module and test the reader.
 216      */
 217     void test(Path mp) throws IOException {
 218 
 219         ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
 220             .newModulePath(Runtime.version(), true, mp);
 221 
 222         ModuleReference mref = finder.find(TEST_MODULE).get();
 223         ModuleReader reader = mref.open();
 224 
 225         try (reader) {
 226 
 227             // test each of the known resources in the module
 228             for (String name : TEST_RESOURCES) {
 229                 byte[] expectedBytes
 230                     = Files.readAllBytes(MODS_DIR
 231                         .resolve(TEST_MODULE)
 232                         .resolve(name.replace('/', File.separatorChar)));
 233 
 234                 testFind(reader, name, expectedBytes);
 235                 testOpen(reader, name, expectedBytes);
 236                 testRead(reader, name, expectedBytes);
 237                 testList(reader, name);
 238             }
 239 
 240             // test "not found"
 241             assertFalse(reader.find(NOT_A_RESOURCE).isPresent());
 242             assertFalse(reader.open(NOT_A_RESOURCE).isPresent());
 243             assertFalse(reader.read(NOT_A_RESOURCE).isPresent());
 244 
 245             // test nulls
 246             try {
 247                 reader.find(null);
 248                 assertTrue(false);
 249             } catch (NullPointerException expected) { }
 250 
 251             try {
 252                 reader.open(null);
 253                 assertTrue(false);
 254             } catch (NullPointerException expected) { }
 255 
 256             try {
 257                 reader.read(null);
 258                 assertTrue(false);
 259             } catch (NullPointerException expected) { }
 260 
 261             try {
 262                 reader.release(null);
 263                 throw new RuntimeException();
 264             } catch (NullPointerException expected) { }
 265 
 266         }
 267 
 268         // test closed ModuleReader
 269         try {
 270             reader.open(TEST_RESOURCES[0]);
 271             assertTrue(false);
 272         } catch (IOException expected) { }
 273 
 274 
 275         try {
 276             reader.read(TEST_RESOURCES[0]);
 277             assertTrue(false);
 278         } catch (IOException expected) { }
 279 
 280         try {
 281             reader.list();
 282             assertTrue(false);
 283         } catch (IOException expected) { }
 284     }
 285 
 286     /**
 287      * Test ModuleReader#find
 288      */
 289     void testFind(ModuleReader reader, String name, byte[] expectedBytes)
 290         throws IOException
 291     {
 292         Optional<URI> ouri = reader.find(name);
 293         assertTrue(ouri.isPresent());
 294 
 295         URL url = ouri.get().toURL();
 296         if (!url.getProtocol().equalsIgnoreCase("jmod")) {
 297             URLConnection uc = url.openConnection();
 298             uc.setUseCaches(false);
 299             try (InputStream in = uc.getInputStream()) {
 300                 byte[] bytes = in.readAllBytes();
 301                 assertTrue(Arrays.equals(bytes, expectedBytes));
 302             }
 303         }
 304     }
 305 
 306     /**
 307      * Test ModuleReader#open
 308      */
 309     void testOpen(ModuleReader reader, String name, byte[] expectedBytes)
 310         throws IOException
 311     {
 312         Optional<InputStream> oin = reader.open(name);
 313         assertTrue(oin.isPresent());
 314 
 315         InputStream in = oin.get();
 316         try (in) {
 317             byte[] bytes = in.readAllBytes();
 318             assertTrue(Arrays.equals(bytes, expectedBytes));
 319         }
 320     }
 321 
 322     /**
 323      * Test ModuleReader#read
 324      */
 325     void testRead(ModuleReader reader, String name, byte[] expectedBytes)
 326         throws IOException
 327     {
 328         Optional<ByteBuffer> obb = reader.read(name);
 329         assertTrue(obb.isPresent());
 330 
 331         ByteBuffer bb = obb.get();
 332         try {
 333             int rem = bb.remaining();
 334             assertTrue(rem == expectedBytes.length);
 335             byte[] bytes = new byte[rem];
 336             bb.get(bytes);
 337             assertTrue(Arrays.equals(bytes, expectedBytes));
 338         } finally {
 339             reader.release(bb);
 340         }
 341     }
 342 
 343     /**
 344      * Test ModuleReader#list
 345      */
 346     void testList(ModuleReader reader, String name) throws IOException {
 347         List<String> list = reader.list().collect(Collectors.toList());
 348         Set<String> names = new HashSet<>(list);
 349         assertTrue(names.size() == list.size()); // no duplicates
 350 
 351         assertTrue(names.contains("module-info.class"));
 352         assertTrue(names.contains(name));
 353 
 354         // all resources should be locatable via find
 355         for (String e : names) {
 356             assertTrue(reader.find(e).isPresent());
 357         }
 358 
 359         // should not contain directories
 360         names.forEach(e -> assertFalse(e.endsWith("/")));
 361     }
 362 
 363 }