1 /*
   2  * Copyright (c) 2015, 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 import java.io.IOException;
  25 import java.nio.file.Files;
  26 import java.nio.file.Path;
  27 import java.nio.file.Paths;
  28 import java.util.ArrayList;
  29 import java.util.List;
  30 import java.util.stream.Collectors;
  31 import java.util.stream.Stream;
  32 
  33 import tests.Helper;
  34 import tests.JImageGenerator;
  35 import tests.Result;
  36 
  37 /*
  38  * @test
  39  * @summary Test custom plugin
  40  * @author Jean-Francois Denise
  41  * @library ../lib
  42  * @modules java.base/jdk.internal.jimage
  43  *          jdk.jdeps/com.sun.tools.classfile
  44  *          jdk.jlink/jdk.tools.jlink.internal
  45  *          jdk.jlink/jdk.tools.jmod
  46  *          jdk.jlink/jdk.tools.jimage
  47  *          jdk.compiler
  48  * @build tests.*
  49  * @run main/othervm CustomPluginTest
  50  */
  51 
  52 public class CustomPluginTest {
  53 
  54     public static void main(String[] args) throws Exception {
  55         new CustomPluginTest().test();
  56     }
  57 
  58     private void test() throws Exception {
  59         Helper helper = Helper.newHelper();
  60         if (helper == null) {
  61             System.err.println("Test not run");
  62             return;
  63         }
  64         helper.generateDefaultModules();
  65         Path jmod = registerServices(helper);
  66         Path pluginModulePath = jmod.getParent();
  67 
  68         testHelloProvider(helper, pluginModulePath);
  69         testCustomPlugins(helper, pluginModulePath);
  70         testModuleVerification(helper, pluginModulePath);
  71     }
  72 
  73     private void testCustomPlugins(Helper helper, Path pluginModulePath) {
  74         Result result = JImageGenerator.getJLinkTask()
  75                 .option("--list-plugins")
  76                 .pluginModulePath(pluginModulePath)
  77                 .output(helper.createNewImageDir("customplugin"))
  78                 .call();
  79         if (result.getExitCode() != 0) {
  80             System.err.println(result.getMessage());
  81             throw new AssertionError("jlink crashed: " + result.getExitCode());
  82         }
  83         List<String> customPlugins = Stream.of(result.getMessage().split("\n"))
  84                 .filter(s -> s.startsWith("Plugin Name:"))
  85                 .filter(s -> s.contains("custom"))
  86                 .collect(Collectors.toList());
  87         if (customPlugins.size() != 1) {
  88             System.err.println(result.getMessage());
  89             throw new AssertionError("Found plugins: " + customPlugins);
  90         }
  91     }
  92 
  93     private Path registerServices(Helper helper) throws IOException {
  94         String name = "customplugin";
  95         Path src = Paths.get(System.getProperty("test.src")).resolve(name);
  96         Path classes = helper.getJmodClassesDir().resolve(name);
  97         JImageGenerator.compile(src, classes);
  98         return JImageGenerator.getJModTask()
  99                 .addClassPath(classes)
 100                 .jmod(helper.getJmodDir().resolve(name + ".jmod"))
 101                 .create().assertSuccess();
 102     }
 103 
 104     private void testHelloProvider(Helper helper, Path pluginModulePath) throws IOException {
 105         Path pluginFile = Paths.get("customplugin.txt");
 106         if (Files.exists(pluginFile)) {
 107             throw new AssertionError("Custom plugin output file already exists");
 108         }
 109         String customplugin = "customplugin";
 110         {
 111             // Add the path but not the option, plugin musn't be called
 112             JImageGenerator.getJLinkTask()
 113                     .modulePath(helper.defaultModulePath())
 114                     .pluginModulePath(pluginModulePath)
 115                     .output(helper.createNewImageDir(customplugin))
 116                     .addMods(customplugin)
 117                     .call().assertSuccess();
 118         }
 119 
 120         if (Files.exists(pluginFile)) {
 121             throw new AssertionError("Custom plugin output file exists, plugin "
 122                     + " called although shouldn't have been");
 123         }
 124 
 125         { // Add the path and the option, plugin should be called.
 126             JImageGenerator.getJLinkTask()
 127                     .modulePath(helper.defaultModulePath())
 128                     .addMods(customplugin)
 129                     .pluginModulePath(pluginModulePath)
 130                     .output(helper.createNewImageDir(customplugin))
 131                     .option("--hello")
 132                     .call().assertSuccess();
 133         }
 134 
 135         if (!Files.exists(pluginFile)) {
 136             throw new AssertionError("Custom plugin not called");
 137         }
 138     }
 139 
 140     private void testModuleVerification(Helper helper, Path pluginModulePath) throws IOException {
 141         {
 142             // dependent module missing check
 143             String moduleName = "bar"; // 8147491
 144             Path jmodFoo = helper.generateDefaultJModule("foo").assertSuccess();
 145             Path jmodBar = helper.generateDefaultJModule(moduleName, "foo").assertSuccess();
 146             // rogue filter removes "foo" module resources which are
 147             // required by "bar" module. Module checks after plugin
 148             // application should detect and report error.
 149             JImageGenerator.getJLinkTask()
 150                 .modulePath(helper.defaultModulePath())
 151                 .pluginModulePath(pluginModulePath)
 152                 .output(helper.createNewImageDir(moduleName))
 153                 .addMods(moduleName)
 154                 .option("--rogue-filter")
 155                 .option("/foo/")
 156                 .call()
 157                 .assertFailure("java.lang.module.ResolutionException");
 158         }
 159 
 160         {
 161             // package exported by one module used as concealed package
 162             // in another module. But, module-info.class is not updated!
 163             String moduleName = "jdk.scripting.nashorn";
 164             JImageGenerator.getJLinkTask()
 165                 .modulePath(helper.defaultModulePath())
 166                 .pluginModulePath(pluginModulePath)
 167                 .output(helper.createNewImageDir(moduleName))
 168                 .addMods(moduleName)
 169                 // "java.logging" includes a package 'javax.script'
 170                 // which is an exported package from "java.scripting" module!
 171                 // module-info.class of java.logging left "as is".
 172                 .option("--rogue-adder")
 173                 .option("/java.logging/javax/script/Foo.class")
 174                 .call()
 175                 .assertFailure(
 176                     "Module java.logging's descriptor returns inconsistent package set");
 177         }
 178     }
 179 }