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 
getJarFilePath(String jarName)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.
build(String jarName, File dir, String man, String ...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 
build(String jarName, String ...classNames)81     public static String build(String jarName, String ...classNames)
82         throws Exception {
83 
84         return createSimpleJar(classDir, getJarFilePath(jarName), classNames);
85     }
86 
build(boolean classesInWorkDir, String jarName, String ...classNames)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 
buildWithManifest(String jarName, String manifest, String jarClassesDir, String ...classNames)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 .
update(String jarFile, String 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 
createSimpleJar(String jarclassDir, String jarName, String[] classNames)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 
addClassArgs(ArrayList<String> args, String jarclassDir, String[] classNames)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 
createModularJar(String jarPath, String classesDir, String mainClass)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 
createJar(ArrayList<String> args)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
getOrCreateHelloJar()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 
compile(String dstPath, String source, String... extraArgs)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 
compileModule(Path src, Path dest, String modulePathArg )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 
signJar()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 
executeProcess(String... cmds)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
printIterable(String msg, Iterable<String> l)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 
printArray(String msg, String[] l)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 }
270