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