ATransformerManagementTestCase.java revision 2362
0N/A/*
2362N/A * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Aimport java.io.*;
0N/Aimport java.lang.instrument.*;
0N/A
0N/Aimport java.security.ProtectionDomain;
0N/Aimport java.util.*;
0N/A
0N/A
0N/A/**
0N/A * Simple tests for the TransformerManager
0N/A *
0N/A */
0N/Apublic abstract class
0N/AATransformerManagementTestCase
0N/A extends AInstrumentationTestCase
0N/A{
0N/A private static final String redefinedClassName = "DummyClass";
0N/A
0N/A protected int kModSamples = 2;
0N/A public final ClassFileTransformer[] kTransformerSamples = new ClassFileTransformer[]
0N/A {
0N/A new MyClassFileTransformer( Integer.toString(0)),
0N/A new MyClassFileTransformer( Integer.toString(1)),
0N/A new MyClassFileTransformer( Integer.toString(2)),
0N/A new MyClassFileTransformer( Integer.toString(3)),
0N/A new MyClassFileTransformer( Integer.toString(4)),
0N/A new MyClassFileTransformer( Integer.toString(5)),
0N/A new MyClassFileTransformer( Integer.toString(6)),
0N/A new MyClassFileTransformer( Integer.toString(7)),
0N/A new MyClassFileTransformer( Integer.toString(8)),
0N/A new MyClassFileTransformer( Integer.toString(9)),
0N/A new MyClassFileTransformer( Integer.toString(10)),
0N/A new MyClassFileTransformer( Integer.toString(11)),
0N/A new MyClassFileTransformer( Integer.toString(12)),
0N/A new MyClassFileTransformer( Integer.toString(13)),
0N/A new MyClassFileTransformer( Integer.toString(14)),
0N/A new MyClassFileTransformer( Integer.toString(15)),
0N/A new MyClassFileTransformer( Integer.toString(16)),
0N/A new MyClassFileTransformer( Integer.toString(17)),
0N/A new MyClassFileTransformer( Integer.toString(18)),
0N/A };
0N/A
0N/A private ArrayList fTransformers; // The list of transformers
0N/A private int fTransformerIndex; // The number of transformers encountered
0N/A private String fDelayedFailure; // Set non-null if failed in transformer
0N/A
0N/A
0N/A /**
0N/A * Constructor for ATransformerManagementTestCase.
0N/A */
0N/A public ATransformerManagementTestCase(String name)
0N/A {
0N/A super(name);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns one of the sample transformers
0N/A * @return a random transformer
0N/A */
0N/A protected ClassFileTransformer
0N/A getRandomTransformer()
0N/A {
0N/A int randIndex = (int)Math.floor(Math.random() * kTransformerSamples.length);
0N/A verbosePrint("Choosing random transformer #" + randIndex);
0N/A return kTransformerSamples[randIndex];
0N/A }
0N/A
0N/A /**
0N/A * Method addTransformerToManager.
0N/A * @param manager
0N/A * @param transformer
0N/A */
0N/A protected void
0N/A addTransformerToManager(
0N/A Instrumentation manager,
0N/A ClassFileTransformer transformer)
0N/A {
0N/A if (transformer != null)
0N/A {
0N/A fTransformers.add(transformer);
0N/A }
0N/A manager.addTransformer(transformer);
0N/A verbosePrint("Added transformer " + transformer);
0N/A }
0N/A
0N/A /**
0N/A * Remove transformer from manager and list
0N/A * @param manager
0N/A * @param transformer
0N/A */
0N/A protected void
0N/A removeTransformerFromManager(
0N/A Instrumentation manager,
0N/A ClassFileTransformer transformer)
0N/A {
0N/A assertTrue("Transformer not found in manager ("+transformer+")", manager.removeTransformer(transformer));
0N/A
0N/A if (transformer != null)
0N/A {
0N/A fTransformers.remove(transformer);
0N/A }
0N/A verbosePrint("Removed transformer " + transformer);
0N/A }
0N/A
0N/A /**
0N/A * Decrements the transformer index as well as removes transformer
0N/A * @param fInst manager
0N/A * @param transformer transformer to remove
0N/A * @param decrementIndex the tranformer index gets out of sync with transformers
0N/A * that are removed from the manager
0N/A */
0N/A protected void
0N/A removeTransformerFromManager( Instrumentation manager,
0N/A ClassFileTransformer transformer,
0N/A boolean decrementIndex)
0N/A {
0N/A removeTransformerFromManager(manager, transformer);
0N/A if (decrementIndex)
0N/A {
0N/A fTransformerIndex--;
0N/A verbosePrint("removeTransformerFromManager fTransformerIndex decremented to: " +
0N/A fTransformerIndex);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * verify transformer by asserting that the number of transforms that occured
0N/A * is the same as the number of valid transformers added to the list.
0N/A * @param manager
0N/A */
0N/A protected void
0N/A verifyTransformers(Instrumentation manager)
0N/A {
0N/A File f = new File(System.getProperty("test.classes", "."), redefinedClassName + ".class");
0N/A System.out.println("Reading test class from " + f);
0N/A try
0N/A {
0N/A InputStream redefineStream = new FileInputStream(f);
0N/A byte[] bytes = NamedBuffer.loadBufferFromStream(redefineStream);
0N/A ClassDefinition cd = new ClassDefinition(DummyClass.class, bytes);
0N/A fInst.redefineClasses(new ClassDefinition[]{ cd });
0N/A verbosePrint("verifyTransformers redefined " + redefinedClassName);
0N/A }
0N/A catch (IOException e)
0N/A {
0N/A fail("Could not load the class: " + redefinedClassName);
0N/A }
0N/A catch (ClassNotFoundException e)
0N/A {
0N/A fail("Could not find the class: " + redefinedClassName);
0N/A }
0N/A catch (UnmodifiableClassException e)
0N/A {
0N/A fail("Could not modify the class: " + redefinedClassName);
0N/A }
0N/A
0N/A // Report any delayed failures
0N/A assertTrue(fDelayedFailure, fDelayedFailure == null);
0N/A
0N/A assertEquals("The number of transformers that were run does not match the expected number added to manager",
0N/A fTransformers.size(), fTransformerIndex);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Asserts that the transformer being checked by the manager is the correct
0N/A * one (as far as order goes) and updates the number of transformers that have
0N/A * been called. Note that since this is being called inside of a transformer,
0N/A * a standard assert (which throws an exception) cannot be used since it would
0N/A * simply cancel the transformation and otherwise be ignored. Instead, note
0N/A * the failure for delayed processing.
0N/A * @param ClassFileTransformer
0N/A */
0N/A private void
0N/A checkInTransformer(ClassFileTransformer transformer)
0N/A {
0N/A verbosePrint("checkInTransformer: " + transformer);
0N/A if (fDelayedFailure == null)
0N/A {
0N/A if (fTransformers.size() <= fTransformerIndex)
0N/A {
0N/A String msg = "The number of transformers that have checked in (" +(fTransformerIndex+1) +
0N/A ") is greater number of tranformers created ("+fTransformers.size()+")";
0N/A fDelayedFailure = msg;
0N/A System.err.println("Delayed failure: " + msg);
0N/A verbosePrint("Delayed failure: " + msg);
0N/A }
0N/A if (!fTransformers.get(fTransformerIndex).equals(transformer))
0N/A {
0N/A String msg = "Transformer " + fTransformers.get(fTransformerIndex) +
0N/A " should be the same as " + transformer;
0N/A fDelayedFailure = msg;
0N/A System.err.println("Delayed failure: " + msg);
0N/A verbosePrint("Delayed failure: " + msg);
0N/A }
0N/A fTransformerIndex++;
0N/A verbosePrint("fTransformerIndex incremented to: " + fTransformerIndex);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Create a new manager, a new transformer list, and initializes the number of transformers
0N/A * indexed to zero.
0N/A */
0N/A protected void
0N/A setUp()
0N/A throws Exception
0N/A {
0N/A super.setUp();
0N/A fTransformers = new ArrayList();
0N/A fTransformerIndex = 0;
0N/A fDelayedFailure = null;
0N/A verbosePrint("setUp completed");
0N/A }
0N/A
0N/A /**
0N/A * Sets the manager and transformers to null so that setUp needs to update.
0N/A */
0N/A protected void
0N/A tearDown()
0N/A throws Exception
0N/A {
0N/A verbosePrint("tearDown beginning");
0N/A fTransformers = null;
0N/A super.tearDown();
0N/A }
0N/A
0N/A /*
0N/A * Simple transformer that registers when it transforms
0N/A */
0N/A public class MyClassFileTransformer extends SimpleIdentityTransformer {
0N/A private final String fID;
0N/A
0N/A public MyClassFileTransformer(String id) {
0N/A super();
0N/A fID = id;
0N/A }
0N/A
0N/A public String toString() {
0N/A return MyClassFileTransformer.this.getClass().getName() + fID;
0N/A }
0N/A
0N/A public byte[]
0N/A transform(
0N/A ClassLoader loader,
0N/A String className,
0N/A Class<?> classBeingRedefined,
0N/A ProtectionDomain protectionDomain,
0N/A byte[] classfileBuffer) {
0N/A
0N/A // The transform testing is triggered by redefine, ignore others
0N/A if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this);
0N/A
0N/A return super.transform( loader,
0N/A className,
0N/A classBeingRedefined,
0N/A protectionDomain,
0N/A classfileBuffer);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Class loader that does nothing
0N/A */
0N/A public class MyClassLoader extends ClassLoader
0N/A {
0N/A /**
0N/A * Constructor for MyClassLoader.
0N/A */
0N/A public MyClassLoader()
0N/A {
0N/A super();
0N/A }
0N/A
0N/A }
0N/A
0N/A public String debug_byteArrayToString(byte[] b) {
0N/A if (b == null) return "null";
0N/A
0N/A StringBuffer buf = new StringBuffer();
0N/A buf.append("byte[");
0N/A buf.append(b.length);
0N/A buf.append("] (");
0N/A for (int i = 0; i < b.length; i++)
0N/A {
0N/A buf.append(b[i]);
0N/A buf.append(",");
0N/A }
0N/A buf.deleteCharAt(buf.length()-1);
0N/A buf.append(")");
0N/A
0N/A return buf.toString();
0N/A }
0N/A}