1 /*
   2  * Copyright (c) 2015, 2020, 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 /*
  26  * @summary Simple jar builder
  27  *   Input: jarName className1 className2 ...
  28  *     do not specify extensions, just the names
  29  *     E.g. prot_domain ProtDomainA ProtDomainB
  30  *   Output: A jar containing compiled classes, placed in a test classes folder
  31  * @library /open/test/lib
  32  */
  33 
  34 import jdk.test.lib.JDKToolFinder;
  35 import jdk.test.lib.compiler.CompilerUtils;
  36 import jdk.test.lib.process.OutputAnalyzer;
  37 import jdk.test.lib.process.ProcessTools;
  38 import java.io.File;
  39 import java.nio.file.Path;
  40 import java.util.ArrayList;
  41 import java.util.spi.ToolProvider;
  42 
  43 public class JarBuilder {
  44     // to turn DEBUG on via command line: -DJarBuilder.DEBUG=[true, TRUE]
  45     private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("JarBuilder.DEBUG", "false"));
  46     private static final String classDir = System.getProperty("test.classes");
  47     private static final ToolProvider JAR = ToolProvider.findFirst("jar")
  48         .orElseThrow(() -> new RuntimeException("ToolProvider for jar not found"));
  49 
  50     public static String getJarFilePath(String jarName) {
  51         return classDir + File.separator + jarName + ".jar";
  52     }
  53 
  54     // jar all files under dir, with manifest file man, with an optional versionArgs
  55     // for generating a multi-release jar.
  56     // The jar command is as follows:
  57     // jar cmf \
  58     //  <path to output jar> <path to the manifest file>\
  59     //   -C <path to the base classes> .\
  60     //    --release 9 -C <path to the versioned classes> .
  61     // the last line begins with "--release" corresponds to the optional versionArgs.
  62     public static void build(String jarName, File dir, String man, String ...versionArgs)
  63         throws Exception {
  64         ArrayList<String> args = new ArrayList<String>();
  65         if (man != null) {
  66             args.add("cfm");
  67         } else {
  68             args.add("cf");
  69         }
  70         args.add(classDir + File.separator + jarName + ".jar");
  71         if (man != null) {
  72             args.add(man);
  73         }
  74         args.add("-C");
  75         args.add(dir.getAbsolutePath());
  76         args.add(".");
  77         for (String verArg : versionArgs) {
  78             args.add(verArg);
  79         }
  80         createJar(args);
  81     }
  82 
  83     public static String build(String jarName, String ...classNames)
  84         throws Exception {
  85 
  86         return createSimpleJar(classDir, getJarFilePath(jarName), classNames);
  87     }
  88 
  89     public static String build(boolean classesInWorkDir, String jarName, String ...classNames)
  90         throws Exception {
  91         if (classesInWorkDir) {
  92             return createSimpleJar(".", getJarFilePath(jarName), classNames);
  93         } else {
  94             return build(jarName, classNames);
  95         }
  96     }
  97 
  98 
  99     public static String buildWithManifest(String jarName, String manifest,
 100         String jarClassesDir, String ...classNames) throws Exception {
 101         String jarPath = getJarFilePath(jarName);
 102         ArrayList<String> args = new ArrayList<String>();
 103         args.add("cvfm");
 104         args.add(jarPath);
 105         args.add(System.getProperty("test.src") + File.separator + "test-classes"
 106             + File.separator + manifest);
 107         addClassArgs(args, jarClassesDir, classNames);
 108         createJar(args);
 109 
 110         return jarPath;
 111     }
 112 
 113 
 114     // Execute: jar uvf $jarFile -C $dir .
 115     static void update(String jarFile, String dir) throws Exception {
 116         String jarExe = JDKToolFinder.getJDKTool("jar");
 117 
 118         ArrayList<String> args = new ArrayList<>();
 119         args.add(jarExe);
 120         args.add("uvf");
 121         args.add(jarFile);
 122         args.add("-C");
 123         args.add(dir);
 124         args.add(".");
 125 
 126         executeProcess(args.toArray(new String[1]));
 127     }
 128 
 129     private static String createSimpleJar(String jarclassDir, String jarName,
 130         String[] classNames) throws Exception {
 131 
 132         ArrayList<String> args = new ArrayList<String>();
 133         args.add("cf");
 134         args.add(jarName);
 135         addClassArgs(args, jarclassDir, classNames);
 136         createJar(args);
 137 
 138         return jarName;
 139     }
 140 
 141     private static void addClassArgs(ArrayList<String> args, String jarclassDir,
 142         String[] classNames) {
 143 
 144         for (String name : classNames) {
 145             args.add("-C");
 146             args.add(jarclassDir);
 147             args.add(name + ".class");
 148         }
 149     }
 150 
 151     public static void createModularJar(String jarPath,
 152                                       String classesDir,
 153                                       String mainClass) throws Exception {
 154         ArrayList<String> argList = new ArrayList<String>();
 155         argList.add("--create");
 156         argList.add("--file=" + jarPath);
 157         if (mainClass != null) {
 158             argList.add("--main-class=" + mainClass);
 159         }
 160         argList.add("-C");
 161         argList.add(classesDir);
 162         argList.add(".");
 163         createJar(argList);
 164     }
 165 
 166     private static void createJar(ArrayList<String> args) {
 167         if (DEBUG) printIterable("createJar args: ", args);
 168 
 169         if (JAR.run(System.out, System.err, args.toArray(new String[1])) != 0) {
 170             throw new RuntimeException("jar operation failed");
 171         }
 172     }
 173 
 174     // Many AppCDS tests use the same simple "hello.jar" which contains
 175     // simple Hello.class and does not specify additional attributes.
 176     // For this common use case, use this method to get the jar path.
 177     // The method will check if the jar already exists
 178     // (created by another test or test run), and will create the jar
 179     // if it does not exist
 180     public static String getOrCreateHelloJar() throws Exception {
 181         String jarPath = getJarFilePath("hello");
 182 
 183         File jarFile = new File(jarPath);
 184         if (jarFile.exists()) {
 185             return jarPath;
 186         } else {
 187             return build("hello", "Hello");
 188         }
 189     }
 190 
 191     public static void compile(String dstPath, String source, String... extraArgs) throws Exception {
 192         ArrayList<String> args = new ArrayList<String>();
 193         args.add(JDKToolFinder.getCompileJDKTool("javac"));
 194         args.add("-d");
 195         args.add(dstPath);
 196         if (extraArgs != null) {
 197             for (String s : extraArgs) {
 198                 args.add(s);
 199             }
 200         }
 201         args.add(source);
 202 
 203         if (DEBUG) printIterable("compile args: ", args);
 204 
 205         ProcessBuilder pb = new ProcessBuilder(args);
 206         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 207         output.shouldHaveExitValue(0);
 208     }
 209 
 210     public static void compileModule(Path src,
 211                                      Path dest,
 212                                      String modulePathArg // arg to --module-path
 213                                      ) throws Exception {
 214         boolean compiled = false;
 215         if (modulePathArg == null) {
 216             compiled = CompilerUtils.compile(src, dest);
 217         } else {
 218             compiled = CompilerUtils.compile(src, dest,
 219                                            "--module-path", modulePathArg);
 220         }
 221         if (!compiled) {
 222             throw new RuntimeException("module did not compile");
 223         }
 224     }
 225 
 226 
 227     public static void signJar() throws Exception {
 228         String keyTool = JDKToolFinder.getJDKTool("keytool");
 229         String jarSigner = JDKToolFinder.getJDKTool("jarsigner");
 230         String classDir = System.getProperty("test.classes");
 231         String FS = File.separator;
 232 
 233         executeProcess(keyTool,
 234             "-genkey", "-keystore", "./keystore", "-alias", "mykey",
 235             "-storepass", "abc123", "-keypass", "abc123", "-keyalg", "dsa",
 236             "-dname", "CN=jvmtest")
 237             .shouldHaveExitValue(0);
 238 
 239         executeProcess(jarSigner,
 240            "-keystore", "./keystore", "-storepass", "abc123", "-keypass",
 241            "abc123", "-signedjar", classDir + FS + "signed_hello.jar",
 242            classDir + FS + "hello.jar", "mykey")
 243            .shouldHaveExitValue(0);
 244     }
 245 
 246     private static OutputAnalyzer executeProcess(String... cmds)
 247         throws Exception {
 248 
 249         JarBuilder.printArray("executeProcess: ", cmds);
 250         return ProcessTools.executeProcess(new ProcessBuilder(cmds));
 251     }
 252 
 253     // diagnostic
 254     public static void printIterable(String msg, Iterable<String> l) {
 255         StringBuilder sum = new StringBuilder();
 256         for (String s : l) {
 257             sum.append(s).append(' ');
 258         }
 259         System.out.println(msg + sum.toString());
 260     }
 261 
 262     public static void printArray(String msg, String[] l) {
 263         StringBuilder sum = new StringBuilder();
 264         for (String s : l) {
 265             sum.append(s).append(' ');
 266         }
 267         System.out.println(msg + sum.toString());
 268     }
 269 }