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