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