Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/testlibrary/ClassFileInstaller.java
32278 views
1
/*
2
* Copyright (c) 2013, 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
import java.io.ByteArrayInputStream;
25
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.FileOutputStream;
28
import java.io.FileNotFoundException;
29
import java.io.InputStream;
30
import java.io.ByteArrayInputStream;
31
import java.nio.file.Files;
32
import java.nio.file.Path;
33
import java.nio.file.Paths;
34
import java.nio.file.StandardCopyOption;
35
import java.util.zip.ZipEntry;
36
import java.util.zip.ZipOutputStream;
37
38
/**
39
* Dump a class file for a class on the class path in the current directory, or
40
* in the specified JAR file. This class is usually used when you build a class
41
* from a test library, but want to use this class in a sub-process.
42
*
43
* For example, to build the following library class:
44
* test/lib/sun/hotspot/WhiteBox.java
45
*
46
* You would use the following tags:
47
*
48
* @library /test/lib
49
* @build sun.hotspot.WhiteBox
50
*
51
* JTREG would build the class file under
52
* ${JTWork}/classes/test/lib/sun/hotspot/WhiteBox.class
53
*
54
* With you run your main test class using "@run main MyMainClass", JTREG would setup the
55
* -classpath to include "${JTWork}/classes/test/lib/", so MyMainClass would be able to
56
* load the WhiteBox class.
57
*
58
* However, if you run a sub process, and do not wish to use the exact same -classpath,
59
* You can use ClassFileInstaller to ensure that WhiteBox is available in the current
60
* directory of your test:
61
*
62
* @run main ClassFileInstaller sun.hotspot.WhiteBox
63
*
64
* Or, you can use the -jar option to store the class in the specified JAR file. If a relative
65
* path name is given, the JAR file would be relative to the current directory of
66
*
67
* @run main ClassFileInstaller -jar myjar.jar sun.hotspot.WhiteBox
68
*/
69
public class ClassFileInstaller {
70
/**
71
* You can enable debug tracing of ClassFileInstaller by running JTREG with
72
* jtreg -DClassFileInstaller.debug=true ... <names of tests>
73
*/
74
public static boolean DEBUG = Boolean.getBoolean("ClassFileInstaller.debug");
75
76
/**
77
* @param args The names of the classes to dump
78
* @throws Exception
79
*/
80
public static void main(String... args) throws Exception {
81
if (args.length > 1 && args[0].equals("-jar")) {
82
if (args.length < 2) {
83
throw new RuntimeException("Usage: ClassFileInstaller <options> <classes>\n" +
84
"where possible options include:\n" +
85
" -jar <path> Write to the JAR file <path>");
86
}
87
writeJar(args[1], null, args, 2, args.length);
88
} else {
89
if (DEBUG) {
90
System.out.println("ClassFileInstaller: Writing to " + System.getProperty("user.dir"));
91
}
92
for (String arg : args) {
93
writeClassToDisk(arg);
94
}
95
}
96
}
97
98
public static class Manifest {
99
private InputStream in;
100
101
private Manifest(InputStream in) {
102
this.in = in;
103
}
104
105
static Manifest fromSourceFile(String fileName) throws Exception {
106
String pathName = System.getProperty("test.src") + File.separator + fileName;
107
return new Manifest(new FileInputStream(pathName));
108
}
109
110
// Example:
111
// String manifest = "Premain-Class: RedefineClassHelper\n" +
112
// "Can-Redefine-Classes: true\n";
113
// ClassFileInstaller.writeJar("redefineagent.jar",
114
// ClassFileInstaller.Manifest.fromString(manifest),
115
// "RedefineClassHelper");
116
static Manifest fromString(String manifest) throws Exception {
117
return new Manifest(new ByteArrayInputStream(manifest.getBytes()));
118
}
119
120
public InputStream getInputStream() {
121
return in;
122
}
123
}
124
125
private static void writeJar(String jarFile, Manifest manifest, String classes[], int from, int to) throws Exception {
126
if (DEBUG) {
127
System.out.println("ClassFileInstaller: Writing to " + getJarPath(jarFile));
128
}
129
130
(new File(jarFile)).delete();
131
FileOutputStream fos = new FileOutputStream(jarFile);
132
ZipOutputStream zos = new ZipOutputStream(fos);
133
134
// The manifest must be the first or second entry. See comments in JarInputStream
135
// constructor and JDK-5046178.
136
if (manifest != null) {
137
writeToDisk(zos, "META-INF/MANIFEST.MF", manifest.getInputStream());
138
}
139
140
for (int i=from; i<to; i++) {
141
writeClassToDisk(zos, classes[i]);
142
}
143
144
zos.close();
145
fos.close();
146
}
147
148
/*
149
* You can call ClassFileInstaller.writeJar() from your main test class instead of
150
* using "@run ClassFileInstaller -jar ...". E.g.,
151
*
152
* String jarPath = ClassFileInstaller.getJarPath("myjar.jar", "sun.hotspot.WhiteBox")
153
*
154
* If you call this API, make sure you build ClassFileInstaller with the following tags:
155
*
156
* @library testlibrary
157
* @build ClassFileInstaller
158
*/
159
public static String writeJar(String jarFile, String... classes) throws Exception {
160
writeJar(jarFile, null, classes, 0, classes.length);
161
return getJarPath(jarFile);
162
}
163
164
public static String writeJar(String jarFile, Manifest manifest, String... classes) throws Exception {
165
writeJar(jarFile, manifest, classes, 0, classes.length);
166
return getJarPath(jarFile);
167
}
168
169
/**
170
* This returns the absolute path to the file specified in "@ClassFileInstaller -jar myjar.jar",
171
* In your test program, instead of using the JAR file name directly:
172
*
173
* String jarPath = "myjar.jar";
174
*
175
* you should call this function, like:
176
*
177
* String jarPath = ClassFileInstaller.getJarPath("myjar.jar")
178
*
179
* The reasons are:
180
* (1) Using absolute path makes it easy to cut-and-paste from the JTR file and rerun your
181
* test in any directory.
182
* (2) In the future, we may make the JAR file name unique to avoid clobbering
183
* during parallel JTREG execution.
184
*
185
*/
186
public static String getJarPath(String jarFileName) {
187
return new File(jarFileName).getAbsolutePath();
188
}
189
190
public static void writeClassToDisk(String className) throws Exception {
191
writeClassToDisk((ZipOutputStream)null, className);
192
}
193
private static void writeClassToDisk(ZipOutputStream zos, String className) throws Exception {
194
writeClassToDisk(zos, className, "");
195
}
196
197
public static void writeClassToDisk(String className, String prependPath) throws Exception {
198
writeClassToDisk(null, className, prependPath);
199
}
200
private static void writeClassToDisk(ZipOutputStream zos, String className, String prependPath) throws Exception {
201
ClassLoader cl = ClassFileInstaller.class.getClassLoader();
202
203
// Convert dotted class name to a path to a class file
204
String pathName = className.replace('.', '/').concat(".class");
205
InputStream is = cl.getResourceAsStream(pathName);
206
if (is == null) {
207
throw new RuntimeException("Failed to find " + pathName);
208
}
209
if (prependPath.length() > 0) {
210
pathName = prependPath + "/" + pathName;
211
}
212
writeToDisk(zos, pathName, is);
213
}
214
215
public static void writeClassToDisk(String className, byte[] bytecode) throws Exception {
216
writeClassToDisk(null, className, bytecode);
217
}
218
private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode) throws Exception {
219
writeClassToDisk(zos, className, bytecode, "");
220
}
221
222
public static void writeClassToDisk(String className, byte[] bytecode, String prependPath) throws Exception {
223
writeClassToDisk(null, className, bytecode, prependPath);
224
}
225
private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode, String prependPath) throws Exception {
226
// Convert dotted class name to a path to a class file
227
String pathName = className.replace('.', '/').concat(".class");
228
if (prependPath.length() > 0) {
229
pathName = prependPath + "/" + pathName;
230
}
231
writeToDisk(zos, pathName, new ByteArrayInputStream(bytecode));
232
}
233
234
private static void writeToDisk(ZipOutputStream zos, String pathName, InputStream is) throws Exception {
235
if (DEBUG) {
236
System.out.println("ClassFileInstaller: Writing " + pathName);
237
}
238
if (zos != null) {
239
ZipEntry ze = new ZipEntry(pathName);
240
zos.putNextEntry(ze);
241
byte[] buf = new byte[1024];
242
int len;
243
while ((len = is.read(buf))>0){
244
zos.write(buf, 0, len);
245
}
246
} else {
247
// Create the class file's package directory
248
Path p = Paths.get(pathName);
249
if (pathName.contains("/")) {
250
Files.createDirectories(p.getParent());
251
}
252
// Create the class file
253
Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
254
}
255
is.close();
256
}
257
}
258
259