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