1 /* 2 * Copyright (c) 2003, 2016, 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 import java.io.*; 26 import java.lang.instrument.*; 27 import java.security.ProtectionDomain; 28 import java.util.*; 29 30 31 /** 32 * Simple tests for the TransformerManager 33 * 34 */ 35 public abstract class 36 ATransformerManagementTestCase 37 extends AInstrumentationTestCase 38 { 39 private static final String redefinedClassName = "DummyClass"; 40 41 protected int kModSamples = 2; 42 public final ClassFileTransformer[] kTransformerSamples = new ClassFileTransformer[] 43 { 44 new MyClassFileTransformer( Integer.toString(0)), 45 new MyClassFileTransformer( Integer.toString(1)), 46 new MyClassFileTransformer( Integer.toString(2)), 47 new MyClassFileTransformer( Integer.toString(3)), 48 new MyClassFileTransformer( Integer.toString(4)), 49 new MyClassFileTransformer( Integer.toString(5)), 50 new MyClassFileTransformer( Integer.toString(6)), 51 new MyClassFileTransformer( Integer.toString(7)), 52 new MyClassFileTransformer( Integer.toString(8)), 53 new MyClassFileTransformer( Integer.toString(9)), 54 new MyClassFileTransformer( Integer.toString(10)), 55 new MyClassFileTransformer( Integer.toString(11)), 56 new MyClassFileTransformer( Integer.toString(12)), 57 new MyClassFileTransformer( Integer.toString(13)), 58 new MyClassFileTransformer( Integer.toString(14)), 59 new MyClassFileTransformer( Integer.toString(15)), 60 new MyClassFileTransformer( Integer.toString(16)), 61 new MyClassFileTransformer( Integer.toString(17)), 62 new MyClassFileTransformer( Integer.toString(18)), 63 }; 64 65 private ArrayList fTransformers; // The list of transformers 66 private int fTransformerIndex; // The number of transformers encountered 67 private String fDelayedFailure; // Set non-null if failed in transformer 68 69 70 /** 71 * Constructor for ATransformerManagementTestCase. 72 */ ATransformerManagementTestCase(String name)73 public ATransformerManagementTestCase(String name) 74 { 75 super(name); 76 } 77 78 79 /** 80 * Returns one of the sample transformers 81 * @return a random transformer 82 */ 83 protected ClassFileTransformer getRandomTransformer()84 getRandomTransformer() 85 { 86 int randIndex = (int)Math.floor(Math.random() * kTransformerSamples.length); 87 verbosePrint("Choosing random transformer #" + randIndex); 88 return kTransformerSamples[randIndex]; 89 } 90 91 /** 92 * Method addTransformerToManager. 93 * @param manager 94 * @param transformer 95 */ 96 protected void addTransformerToManager( Instrumentation manager, ClassFileTransformer transformer)97 addTransformerToManager( 98 Instrumentation manager, 99 ClassFileTransformer transformer) 100 { 101 addTransformerToManager(manager, transformer, false); 102 } 103 104 /** 105 * Method addTransformerToManager. 106 * @param manager 107 * @param transformer 108 * @param canRetransform 109 */ 110 protected void addTransformerToManager( Instrumentation manager, ClassFileTransformer transformer, boolean canRetransform)111 addTransformerToManager( 112 Instrumentation manager, 113 ClassFileTransformer transformer, 114 boolean canRetransform) 115 { 116 if (transformer != null) 117 { 118 fTransformers.add(transformer); 119 } 120 manager.addTransformer(transformer, canRetransform); 121 verbosePrint("Added transformer " + transformer 122 + " with canRetransform=" + canRetransform); 123 } 124 125 /** 126 * Remove transformer from manager and list 127 * @param manager 128 * @param transformer 129 */ 130 protected void removeTransformerFromManager( Instrumentation manager, ClassFileTransformer transformer)131 removeTransformerFromManager( 132 Instrumentation manager, 133 ClassFileTransformer transformer) 134 { 135 assertTrue("Transformer not found in manager ("+transformer+")", manager.removeTransformer(transformer)); 136 137 if (transformer != null) 138 { 139 fTransformers.remove(transformer); 140 } 141 verbosePrint("Removed transformer " + transformer); 142 } 143 144 /** 145 * Decrements the transformer index as well as removes transformer 146 * @param fInst manager 147 * @param transformer transformer to remove 148 * @param decrementIndex the tranformer index gets out of sync with transformers 149 * that are removed from the manager 150 */ 151 protected void removeTransformerFromManager( Instrumentation manager, ClassFileTransformer transformer, boolean decrementIndex)152 removeTransformerFromManager( Instrumentation manager, 153 ClassFileTransformer transformer, 154 boolean decrementIndex) 155 { 156 removeTransformerFromManager(manager, transformer); 157 if (decrementIndex) 158 { 159 fTransformerIndex--; 160 verbosePrint("removeTransformerFromManager fTransformerIndex decremented to: " + 161 fTransformerIndex); 162 } 163 } 164 165 /** 166 * verify transformer by asserting that the number of transforms that occured 167 * is the same as the number of valid transformers added to the list. 168 * @param manager 169 */ 170 protected void verifyTransformers(Instrumentation manager)171 verifyTransformers(Instrumentation manager) 172 { 173 File f = new File(System.getProperty("test.classes", "."), redefinedClassName + ".class"); 174 System.out.println("Reading test class from " + f); 175 try 176 { 177 InputStream redefineStream = new FileInputStream(f); 178 byte[] bytes = NamedBuffer.loadBufferFromStream(redefineStream); 179 ClassDefinition cd = new ClassDefinition(DummyClass.class, bytes); 180 fInst.redefineClasses(new ClassDefinition[]{ cd }); 181 verbosePrint("verifyTransformers redefined " + redefinedClassName); 182 } 183 catch (IOException e) 184 { 185 fail("Could not load the class: " + redefinedClassName); 186 } 187 catch (ClassNotFoundException e) 188 { 189 fail("Could not find the class: " + redefinedClassName); 190 } 191 catch (UnmodifiableClassException e) 192 { 193 fail("Could not modify the class: " + redefinedClassName); 194 } 195 196 // Report any delayed failures 197 assertTrue(fDelayedFailure, fDelayedFailure == null); 198 199 assertEquals("The number of transformers that were run does not match the expected number added to manager", 200 fTransformers.size(), fTransformerIndex); 201 } 202 203 204 /** 205 * Asserts that the transformer being checked by the manager is the correct 206 * one (as far as order goes) and updates the number of transformers that have 207 * been called. Note that since this is being called inside of a transformer, 208 * a standard assert (which throws an exception) cannot be used since it would 209 * simply cancel the transformation and otherwise be ignored. Instead, note 210 * the failure for delayed processing. 211 * @param ClassFileTransformer 212 */ 213 private void checkInTransformer(ClassFileTransformer transformer)214 checkInTransformer(ClassFileTransformer transformer) 215 { 216 verbosePrint("checkInTransformer: " + transformer); 217 if (fDelayedFailure == null) 218 { 219 if (fTransformers.size() <= fTransformerIndex) 220 { 221 String msg = "The number of transformers that have checked in (" +(fTransformerIndex+1) + 222 ") is greater number of tranformers created ("+fTransformers.size()+")"; 223 fDelayedFailure = msg; 224 System.err.println("Delayed failure: " + msg); 225 verbosePrint("Delayed failure: " + msg); 226 } 227 if (!fTransformers.get(fTransformerIndex).equals(transformer)) 228 { 229 String msg = "Transformer " + fTransformers.get(fTransformerIndex) + 230 " should be the same as " + transformer; 231 fDelayedFailure = msg; 232 System.err.println("Delayed failure: " + msg); 233 verbosePrint("Delayed failure: " + msg); 234 } 235 fTransformerIndex++; 236 verbosePrint("fTransformerIndex incremented to: " + fTransformerIndex); 237 } 238 } 239 240 /** 241 * Create a new manager, a new transformer list, and initializes the number of transformers 242 * indexed to zero. 243 */ 244 protected void setUp()245 setUp() 246 throws Exception 247 { 248 super.setUp(); 249 fTransformers = new ArrayList(); 250 fTransformerIndex = 0; 251 fDelayedFailure = null; 252 verbosePrint("setUp completed"); 253 } 254 255 /** 256 * Sets the manager and transformers to null so that setUp needs to update. 257 */ 258 protected void tearDown()259 tearDown() 260 throws Exception 261 { 262 verbosePrint("tearDown beginning"); 263 fTransformers = null; 264 super.tearDown(); 265 } 266 267 /* 268 * Simple transformer that registers when it transforms 269 */ 270 public class MyClassFileTransformer extends SimpleIdentityTransformer { 271 private final String fID; 272 MyClassFileTransformer(String id)273 public MyClassFileTransformer(String id) { 274 super(); 275 fID = id; 276 } 277 toString()278 public String toString() { 279 return MyClassFileTransformer.this.getClass().getName() + fID; 280 } 281 282 public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)283 transform( 284 ClassLoader loader, 285 String className, 286 Class<?> classBeingRedefined, 287 ProtectionDomain protectionDomain, 288 byte[] classfileBuffer) { 289 290 // The transform testing is triggered by redefine, ignore others 291 if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); 292 293 return super.transform( loader, 294 className, 295 classBeingRedefined, 296 protectionDomain, 297 classfileBuffer); 298 } 299 300 public byte[] transform( Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)301 transform( 302 Module module, 303 ClassLoader loader, 304 String className, 305 Class<?> classBeingRedefined, 306 ProtectionDomain protectionDomain, 307 byte[] classfileBuffer) { 308 309 // The transform testing is triggered by redefine, ignore others 310 if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); 311 312 return super.transform( module, 313 loader, 314 className, 315 classBeingRedefined, 316 protectionDomain, 317 classfileBuffer); 318 } 319 } 320 321 322 /** 323 * Class loader that does nothing 324 */ 325 public class MyClassLoader extends ClassLoader 326 { 327 /** 328 * Constructor for MyClassLoader. 329 */ MyClassLoader()330 public MyClassLoader() 331 { 332 super(); 333 } 334 335 } 336 debug_byteArrayToString(byte[] b)337 public String debug_byteArrayToString(byte[] b) { 338 if (b == null) return "null"; 339 340 StringBuffer buf = new StringBuffer(); 341 buf.append("byte["); 342 buf.append(b.length); 343 buf.append("] ("); 344 for (int i = 0; i < b.length; i++) 345 { 346 buf.append(b[i]); 347 buf.append(","); 348 } 349 buf.deleteCharAt(buf.length()-1); 350 buf.append(")"); 351 352 return buf.toString(); 353 } 354 } 355