1 /* 2 * Copyright (c) 2012, 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.*; 25 import java.lang.instrument.Instrumentation; 26 import java.lang.instrument.ClassFileTransformer; 27 import java.net.*; 28 import java.security.ProtectionDomain; 29 30 public class 31 VerifyLocalVariableTableOnRetransformTest 32 extends ATransformerManagementTestCase 33 { 34 private byte[] fTargetClassBytes; 35 private boolean fTargetClassMatches; 36 private String fTargetClassName = "DummyClassWithLVT"; 37 private boolean fTargetClassSeen; 38 39 /** 40 * Constructor for VerifyLocalVariableTableOnRetransformTest. 41 * @param name 42 */ 43 public VerifyLocalVariableTableOnRetransformTest(String name) 44 { 45 super(name); 46 47 String resourceName = fTargetClassName + ".class"; 48 File f = new File(System.getProperty("test.classes", "."), resourceName); 49 System.out.println("Reading test class from " + f); 50 try 51 { 52 InputStream redefineStream = new FileInputStream(f); 53 fTargetClassBytes = NamedBuffer.loadBufferFromStream(redefineStream); 54 System.out.println("Read " + fTargetClassBytes.length + " bytes."); 55 } 56 catch (IOException e) 57 { 58 fail("Could not load the class: "+resourceName); 59 } 60 } 61 62 public static void 63 main (String[] args) 64 throws Throwable { 65 ATestCaseScaffold test = new VerifyLocalVariableTableOnRetransformTest(args[0]); 66 test.runTest(); 67 } 68 69 protected final void 70 doRunTest() 71 throws Throwable { 72 verifyClassFileBuffer(); 73 } 74 75 public void 76 verifyClassFileBuffer() 77 throws Throwable 78 { 79 beVerbose(); 80 81 // With this call here, we will see the target class twice: 82 // first when it gets loaded and second when it gets retransformed. 83 addTransformerToManager(fInst, new MyObserver(), true); 84 85 ClassLoader loader = getClass().getClassLoader(); 86 87 Class target = loader.loadClass(fTargetClassName); 88 assertEquals(fTargetClassName, target.getName()); 89 90 // make an instance to prove the class was really loaded 91 Object testInstance = target.newInstance(); 92 93 // With this call here, we will see the target class once: 94 // when it gets retransformed. 95 //addTransformerToManager(fInst, new MyObserver(), true); 96 97 assertTrue(fTargetClassName + " was not seen by transform()", 98 fTargetClassSeen); 99 100 // The HotSpot VM hands us class file bytes at initial class 101 // load time that match the .class file contents. However, 102 // according to the following spec that is not required: 103 // http://javaweb.sfbay/javare/jdk/6.0/promoted/latest/doc/api/java/lang/instrument/Instrumentation.html#retransformClasses(java.lang.Class...) 104 // This test exists to catch any unintentional change in 105 // behavior by the HotSpot VM. If this behavior is intentionally 106 // changed in the future, then this test will need to be 107 // updated. 108 assertTrue(fTargetClassName + " did not match .class file", 109 fTargetClassMatches); 110 111 fTargetClassSeen = false; 112 fTargetClassMatches = false; 113 114 fInst.retransformClasses(target); 115 116 assertTrue(fTargetClassName + " was not seen by transform()", 117 fTargetClassSeen); 118 119 // The HotSpot VM doesn't currently preserve the LocalVariable 120 // Table (LVT) attribute so the class file bytes seen by the 121 // retransformClasses() call will not match the class file bytes 122 // seen at initial class load time. 123 assertTrue(fTargetClassName + " did not match .class file", 124 fTargetClassMatches); 125 } 126 127 public class MyObserver implements ClassFileTransformer { 128 public MyObserver() { 129 } 130 131 public String toString() { 132 return MyObserver.this.getClass().getName(); 133 } 134 135 private void saveMismatchedBytes(byte[] classfileBuffer) { 136 try { 137 FileOutputStream fos = null; 138 // This file will get created in the test execution 139 // directory so there is no conflict with the file 140 // in the test classes directory. 141 String resourceName = fTargetClassName + ".class"; 142 fos = new FileOutputStream(resourceName); 143 fos.write(classfileBuffer); 144 fos.close(); 145 } catch (IOException ex) { 146 } 147 } 148 149 public byte[] 150 transform( 151 ClassLoader loader, 152 String className, 153 Class<?> classBeingRedefined, 154 ProtectionDomain protectionDomain, 155 byte[] classfileBuffer) { 156 157 System.out.println(this + ".transform() sees '" + className 158 + "' of " + classfileBuffer.length + " bytes."); 159 if (className.equals(fTargetClassName)) { 160 fTargetClassSeen = true; 161 162 if (classfileBuffer.length != fTargetClassBytes.length) { 163 System.out.println("Warning: " + fTargetClassName 164 + " lengths do not match."); 165 fTargetClassMatches = false; 166 saveMismatchedBytes(classfileBuffer); 167 return null; 168 } else { 169 System.out.println("Info: " + fTargetClassName 170 + " lengths match."); 171 } 172 173 for (int i = 0; i < classfileBuffer.length; i++) { 174 if (classfileBuffer[i] != fTargetClassBytes[i]) { 175 System.out.println("Warning: " + fTargetClassName 176 + "[" + i + "]: '" + classfileBuffer[i] 177 + "' != '" + fTargetClassBytes[i] + "'"); 178 fTargetClassMatches = false; 179 saveMismatchedBytes(classfileBuffer); 180 return null; 181 } 182 } 183 184 fTargetClassMatches = true; 185 System.out.println("Info: verified '" + fTargetClassName 186 + ".class' matches 'classfileBuffer'."); 187 } 188 189 return null; 190 } 191 } 192 }