1 /*
   2  * Copyright (c) 2015, 2018, 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 sun.tools.jar.Main;
  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 
  48     public static String getJarFilePath(String jarName) {
  49         return classDir + File.separator + jarName + ".jar";
  50     }
  51 
  52     // jar all files under dir, with manifest file man, with an optional versionArgs
  53     // for generating a multi-release jar.
  54     // The jar command is as follows:
  55     // jar cmf \
  56     //  <path to output jar> <path to the manifest file>\
  57     //   -C <path to the base classes> .\
  58     //    --release 9 -C <path to the versioned classes> .
  59     // the last line begins with "--release" corresponds to the optional versionArgs.
  60     public static void build(String jarName, File dir, String man, String ...versionArgs)
  61         throws Exception {
  62         ArrayList<String> args = new ArrayList<String>();
  63         if (man != null) {
  64             args.add("cfm");
  65         } else {
  66             args.add("cf");
  67         }
  68         args.add(classDir + File.separator + jarName + ".jar");
  69         if (man != null) {
  70             args.add(man);
  71         }
  72         args.add("-C");
  73         args.add(dir.getAbsolutePath());
  74         args.add(".");
  75         for (String verArg : versionArgs) {
  76             args.add(verArg);
  77         }
  78         createJar(args);
  79     }
  80 
  81     public static String build(String jarName, String ...classNames)
  82         throws Exception {
  83 
  84         return createSimpleJar(classDir, getJarFilePath(jarName), classNames);
  85     }
  86 
  87     public static String build(boolean classesInWorkDir, String jarName, String ...classNames)
  88         throws Exception {
  89         if (classesInWorkDir) {
  90             return createSimpleJar(".", getJarFilePath(jarName), classNames);
  91         } else {
  92             return build(jarName, classNames);
  93         }
  94     }
  95 
  96 
  97     public static String buildWithManifest(String jarName, String manifest,
  98         String jarClassesDir, String ...classNames) throws Exception {
  99         String jarPath = getJarFilePath(jarName);
 100         ArrayList<String> args = new ArrayList<String>();
 101         args.add("cvfm");
 102         args.add(jarPath);
 103         args.add(System.getProperty("test.src") + File.separator + "test-classes"
 104             + File.separator + manifest);
 105         addClassArgs(args, jarClassesDir, classNames);
 106         createJar(args);
 107 
 108         return jarPath;
 109     }
 110 
 111 
 112     // Execute: jar uvf $jarFile -C $dir .
 113     static void update(String jarFile, String dir) throws Exception {
 114         String jarExe = JDKToolFinder.getJDKTool("jar");
 115 
 116         ArrayList<String> args = new ArrayList<>();
 117         args.add(jarExe);
 118         args.add("uvf");
 119         args.add(jarFile);
 120         args.add("-C");
 121         args.add(dir);
 122         args.add(".");
 123 
 124         executeProcess(args.toArray(new String[1]));
 125     }
 126 
 127 
 128     private static String createSimpleJar(String jarclassDir, String jarName,
 129         String[] classNames) throws Exception {
 130 
 131         ArrayList<String> args = new ArrayList<String>();
 132         args.add("cf");
 133         args.add(jarName);
 134         addClassArgs(args, jarclassDir, classNames);
 135         createJar(args);
 136 
 137         return jarName;
 138     }
 139 
 140     private static void addClassArgs(ArrayList<String> args, String jarclassDir,
 141         String[] classNames) {
 142 
 143         for (String name : classNames) {
 144             args.add("-C");
 145             args.add(jarclassDir);
 146             args.add(name + ".class");
 147         }
 148     }
 149 
 150     public static void createModularJar(String jarPath,
 151                                       String classesDir,
 152                                       String mainClass) throws Exception {
 153         ArrayList<String> argList = new ArrayList<String>();
 154         argList.add("--create");
 155         argList.add("--file=" + jarPath);
 156         if (mainClass != null) {
 157             argList.add("--main-class=" + mainClass);
 158         }
 159         argList.add("-C");
 160         argList.add(classesDir);
 161         argList.add(".");
 162         createJar(argList);
 163     }
 164 
 165     private static void createJar(ArrayList<String> args) {
 166         if (DEBUG) printIterable("createJar args: ", args);
 167 
 168         Main jarTool = new Main(System.out, System.err, "jar");
 169         if (!jarTool.run(args.toArray(new String[1]))) {
 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",
 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 }