1 /*
   2  * Copyright (c) 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.jfr.event.oldobject;
  27 
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import java.io.ByteArrayOutputStream;
  33 
  34 /*
  35  * A special class loader that will, for our test class, make sure that each
  36  * load will become a unique class
  37  */
  38 public final class TestClassLoader extends ClassLoader {
  39 
  40     public static final class TestClass0000000 {
  41         public static final byte[] oneByte = new byte[1];
  42     }
  43 
  44     static byte[] classByteCode = readTestClassBytes();
  45     private static int classIdCounter;
  46 
  47     TestClassLoader() {
  48         super(TestClassLoader.class.getClassLoader());
  49     }
  50 
  51     public List<Class<?>> loadClasses(int count) throws Exception {
  52         List<Class<?>> classes = new ArrayList<>();
  53         for (int i = 0; i < count; i++) {
  54             String className = "jdk.jfr.event.oldobject.TestClassLoader$";
  55             className += "TestClass" + String.format("%07d", classIdCounter++);
  56             Class<?> clazz = Class.forName(className, true, this);
  57             classes.add(clazz);
  58         }
  59         return classes;
  60     }
  61 
  62     @Override
  63     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
  64         // If not loading the test class, just go on with the normal class loader
  65         if (!name.contains("TestClass")) {
  66             return super.loadClass(name, resolve);
  67         }
  68         String[] classNameParts = name.split("\\$");
  69         String newName = classNameParts[1];
  70         String oldName = "TestClass0000000";
  71         if (oldName.length() != newName.length()) {
  72             throw new AssertionError("String lengths don't match. Unable to replace class name");
  73         }
  74         byte[] newBytes = classByteCode.clone();
  75         replaceBytes(newBytes, oldName.getBytes(), newName.getBytes());
  76         Class<?> c = defineClass(name, newBytes, 0, newBytes.length);
  77         if (resolve) {
  78             resolveClass(c);
  79         }
  80         return c;
  81     }
  82 
  83     static void replaceBytes(byte[] bytes, byte[] find, byte[] replacement) {
  84         for (int index = 0; index < bytes.length - find.length; index++) {
  85             if (matches(bytes, index, find)) {
  86                 replace(bytes, index, replacement);
  87             }
  88         }
  89     }
  90 
  91     private static void replace(byte[] bytes, int startIndex, byte[] replacement) {
  92         for (int index = 0; index < replacement.length; index++) {
  93             bytes[startIndex + index] = replacement[index];
  94         }
  95     }
  96 
  97     private static boolean matches(byte[] bytes, int startIndex, byte[] matching) {
  98         for (int i = 0; i < matching.length; i++) {
  99             if (bytes[startIndex + i] != matching[i]) {
 100                 return false;
 101             }
 102         }
 103         return true;
 104     }
 105 
 106     private static byte[] readTestClassBytes() {
 107         try {
 108             String classFileName = "jdk/jfr/event/oldobject/TestClassLoader$TestClass0000000.class";
 109             InputStream is = TestClassLoader.class.getClassLoader().getResourceAsStream(classFileName);
 110             if (is == null) {
 111                 throw new RuntimeException("Culd not find class file " + classFileName);
 112             }
 113             //byte[] b;= is.readAllBytes();
 114             //is.read(b);
 115             ByteArrayOutputStream os = new ByteArrayOutputStream();
 116             byte[] buffer = new byte[0xFFFF];
 117             for (int len = is.read(buffer); len != -1; len = is.read(buffer)) {
 118                 os.write(buffer, 0, len);
 119             }
 120             is.close();
 121             return os.toByteArray();
 122         } catch (IOException ioe) {
 123             ioe.printStackTrace();
 124             throw new RuntimeException(ioe);
 125         }
 126     }
 127 }