1 /* 2 * Copyright (c) 2003, 2021, 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 // workaroud for JDK-8264667: create log message before addTransformer() 121 String msg = "Added transformer " + transformer 122 + " with canRetransform=" + canRetransform; 123 manager.addTransformer(transformer, canRetransform); 124 verbosePrint(msg); 125 } 126 127 /** 128 * Remove transformer from manager and list 129 * @param manager 130 * @param transformer 131 */ 132 protected void removeTransformerFromManager( Instrumentation manager, ClassFileTransformer transformer)133 removeTransformerFromManager( 134 Instrumentation manager, 135 ClassFileTransformer transformer) 136 { 137 assertTrue("Transformer not found in manager ("+transformer+")", manager.removeTransformer(transformer)); 138 139 if (transformer != null) 140 { 141 fTransformers.remove(transformer); 142 } 143 verbosePrint("Removed transformer " + transformer); 144 } 145 146 /** 147 * Decrements the transformer index as well as removes transformer 148 * @param fInst manager 149 * @param transformer transformer to remove 150 * @param decrementIndex the tranformer index gets out of sync with transformers 151 * that are removed from the manager 152 */ 153 protected void removeTransformerFromManager( Instrumentation manager, ClassFileTransformer transformer, boolean decrementIndex)154 removeTransformerFromManager( Instrumentation manager, 155 ClassFileTransformer transformer, 156 boolean decrementIndex) 157 { 158 removeTransformerFromManager(manager, transformer); 159 if (decrementIndex) 160 { 161 fTransformerIndex--; 162 verbosePrint("removeTransformerFromManager fTransformerIndex decremented to: " + 163 fTransformerIndex); 164 } 165 } 166 167 /** 168 * verify transformer by asserting that the number of transforms that occured 169 * is the same as the number of valid transformers added to the list. 170 * @param manager 171 */ 172 protected void verifyTransformers(Instrumentation manager)173 verifyTransformers(Instrumentation manager) 174 { 175 File f = new File(System.getProperty("test.classes", "."), redefinedClassName + ".class"); 176 System.out.println("Reading test class from " + f); 177 try 178 { 179 InputStream redefineStream = new FileInputStream(f); 180 byte[] bytes = NamedBuffer.loadBufferFromStream(redefineStream); 181 ClassDefinition cd = new ClassDefinition(DummyClass.class, bytes); 182 fInst.redefineClasses(new ClassDefinition[]{ cd }); 183 verbosePrint("verifyTransformers redefined " + redefinedClassName); 184 } 185 catch (IOException e) 186 { 187 fail("Could not load the class: " + redefinedClassName); 188 } 189 catch (ClassNotFoundException e) 190 { 191 fail("Could not find the class: " + redefinedClassName); 192 } 193 catch (UnmodifiableClassException e) 194 { 195 fail("Could not modify the class: " + redefinedClassName); 196 } 197 198 // Report any delayed failures 199 assertTrue(fDelayedFailure, fDelayedFailure == null); 200 201 assertEquals("The number of transformers that were run does not match the expected number added to manager", 202 fTransformers.size(), fTransformerIndex); 203 } 204 205 206 /** 207 * Asserts that the transformer being checked by the manager is the correct 208 * one (as far as order goes) and updates the number of transformers that have 209 * been called. Note that since this is being called inside of a transformer, 210 * a standard assert (which throws an exception) cannot be used since it would 211 * simply cancel the transformation and otherwise be ignored. Instead, note 212 * the failure for delayed processing. 213 * @param ClassFileTransformer 214 */ 215 private void checkInTransformer(ClassFileTransformer transformer)216 checkInTransformer(ClassFileTransformer transformer) 217 { 218 verbosePrint("checkInTransformer: " + transformer); 219 if (fDelayedFailure == null) 220 { 221 if (fTransformers.size() <= fTransformerIndex) 222 { 223 String msg = "The number of transformers that have checked in (" +(fTransformerIndex+1) + 224 ") is greater number of tranformers created ("+fTransformers.size()+")"; 225 fDelayedFailure = msg; 226 System.err.println("Delayed failure: " + msg); 227 verbosePrint("Delayed failure: " + msg); 228 } 229 if (!fTransformers.get(fTransformerIndex).equals(transformer)) 230 { 231 String msg = "Transformer " + fTransformers.get(fTransformerIndex) + 232 " should be the same as " + transformer; 233 fDelayedFailure = msg; 234 System.err.println("Delayed failure: " + msg); 235 verbosePrint("Delayed failure: " + msg); 236 } 237 fTransformerIndex++; 238 verbosePrint("fTransformerIndex incremented to: " + fTransformerIndex); 239 } 240 } 241 242 /** 243 * Create a new manager, a new transformer list, and initializes the number of transformers 244 * indexed to zero. 245 */ 246 protected void setUp()247 setUp() 248 throws Exception 249 { 250 super.setUp(); 251 fTransformers = new ArrayList(); 252 fTransformerIndex = 0; 253 fDelayedFailure = null; 254 verbosePrint("setUp completed"); 255 } 256 257 /** 258 * Sets the manager and transformers to null so that setUp needs to update. 259 */ 260 protected void tearDown()261 tearDown() 262 throws Exception 263 { 264 verbosePrint("tearDown beginning"); 265 fTransformers = null; 266 super.tearDown(); 267 } 268 269 /* 270 * Simple transformer that registers when it transforms 271 */ 272 public class MyClassFileTransformer extends SimpleIdentityTransformer { 273 private final String fID; 274 MyClassFileTransformer(String id)275 public MyClassFileTransformer(String id) { 276 super(); 277 fID = id; 278 } 279 toString()280 public String toString() { 281 return MyClassFileTransformer.this.getClass().getName() + fID; 282 } 283 284 public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)285 transform( 286 ClassLoader loader, 287 String className, 288 Class<?> classBeingRedefined, 289 ProtectionDomain protectionDomain, 290 byte[] classfileBuffer) { 291 292 // The transform testing is triggered by redefine, ignore others 293 if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); 294 295 return super.transform( loader, 296 className, 297 classBeingRedefined, 298 protectionDomain, 299 classfileBuffer); 300 } 301 302 public byte[] transform( Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)303 transform( 304 Module module, 305 ClassLoader loader, 306 String className, 307 Class<?> classBeingRedefined, 308 ProtectionDomain protectionDomain, 309 byte[] classfileBuffer) { 310 311 // The transform testing is triggered by redefine, ignore others 312 if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); 313 314 return super.transform( module, 315 loader, 316 className, 317 classBeingRedefined, 318 protectionDomain, 319 classfileBuffer); 320 } 321 } 322 323 324 /** 325 * Class loader that does nothing 326 */ 327 public class MyClassLoader extends ClassLoader 328 { 329 /** 330 * Constructor for MyClassLoader. 331 */ MyClassLoader()332 public MyClassLoader() 333 { 334 super(); 335 } 336 337 } 338 debug_byteArrayToString(byte[] b)339 public String debug_byteArrayToString(byte[] b) { 340 if (b == null) return "null"; 341 342 StringBuffer buf = new StringBuffer(); 343 buf.append("byte["); 344 buf.append(b.length); 345 buf.append("] ("); 346 for (int i = 0; i < b.length; i++) 347 { 348 buf.append(b[i]); 349 buf.append(","); 350 } 351 buf.deleteCharAt(buf.length()-1); 352 buf.append(")"); 353 354 return buf.toString(); 355 } 356 } 357