< prev index next >

test/lib/testlibrary/ClassFileInstaller.java

Print this page
rev 13660 : 8229501: jdk/test/lib/testlibrary/ClassFileInstaller.java should match hotspot//test/testlibrary version
   1 /*
   2  * Copyright (c) 2013, 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.InputStream;

  25 import java.nio.file.Files;
  26 import java.nio.file.Path;
  27 import java.nio.file.Paths;
  28 import java.nio.file.StandardCopyOption;


  29 
  30 /**
  31  * Dump a class file for a class on the class path in the current directory




























  32  */
  33 public class ClassFileInstaller {
  34     /**






  35      * @param args The names of the classes to dump
  36      * @throws Exception
  37      */
  38     public static void main(String... args) throws Exception {











  39         for (String arg : args) {












































































































  40             ClassLoader cl = ClassFileInstaller.class.getClassLoader();
  41 
  42             // Convert dotted class name to a path to a class file
  43             String pathName = arg.replace('.', '/').concat(".class");
  44             InputStream is = cl.getResourceAsStream(pathName);








  45 
































  46             // Create the class file's package directory
  47             Path p = Paths.get(pathName);
  48             Path parent = p.getParent();
  49             if (parent != null) {
  50                 Files.createDirectories(parent);
  51             }
  52             // Create the class file
  53             Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
  54         }

  55     }
  56 }
   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 }
< prev index next >