Package ch.ethz.prose

Source Code of ch.ethz.prose.HotSwapTest$TestRedefineClasses

//  $Id: HotSwapTest.java,v 1.2 2008/11/18 10:33:25 anicoara Exp $
//  =====================================================================

package ch.ethz.prose;

// used packages
import java.lang.reflect.*;
import junit.framework.*;

import ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl;
import ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver;
import ch.ethz.inf.iks.jvmai.jvmdi.HotSwapProvider;
import ch.ethz.jvmai.*;

import java.io.InputStream;
//import org.apache.bcel.classfile.*;
import org.apache.bcel.classfile.ClassParser;
//import org.apache.bcel.verifier.*;
//import org.apache.bcel.classfile.ClassFormatException;  // could not resolve this class
import org.apache.bcel.classfile.JavaClass;          // not yet used
import org.apache.bcel.generic.*;

/**
* JUnit testcase for class HotSwapProvider.
*
* @version $Revision: 1.2 $
* @author  Angela Nicoara
* @author  Gerald Linhofer
*/
public class HotSwapTest extends TestCase {

  HotSwapAspectInterfaceImpl aspectInterface;

  //----------------------------------------------------------------------------------------------------------------------
  private static void staticMethod() { return; }
  public static double staticField = 3;

  class MyDummy {
    private int privateField = 1;
    public int publicField = 2;
    public int publicMethod() { return 1; }
    private void privateMethod() { return; }
  }

  class MyDummy2 {
    private int privateField = 1;
    public int publicField = 2;
    public int publicMethod() { return privateField; }
    private void privateMethod() { return; }
  }

  class MyAspectInterface extends HotSwapAspectInterfaceImpl {

    private int dummy;

    /**
     * Tests {@link ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl#getMethodFromString
     * getMethodFromString(java.lang.String)}.
     *
     */
    void testGetMethodFromString() {
      // do some calls with invalid parameters
      int catcheExceptions = 0;
      try{
        try{ getMethodFromString(null); }
        catch(NullPointerException e) { catcheExceptions++; }
        try{ getMethodFromString("class"); }
        catch(InvalidIdException e) { catcheExceptions++; }
        try{ getMethodFromString("class#method"); }
        catch(InvalidIdException e) { catcheExceptions++; }
        try{ getMethodFromString("class#method#(I)Z"); }
        catch(ClassNotFoundException e) { catcheExceptions++; }
        try{ getMethodFromString(this.getClass().getName() + "#method#(I)Z"); }
        catch(NoSuchMethodError e) { catcheExceptions++; }
        try{ getMethodFromString(this.getClass().getName() + "#testGetMethodFromString#(I)Z"); }
        catch(NoSuchMethodError e) { catcheExceptions++; }
      } catch(Exception e) { fail("throws wrong assertion" + e.getClass().getName()); }
      assertEquals("number of catched assertions", 6, catcheExceptions);

      // try to get this method.
      Member thisMethod = this.getClass().getDeclaredMethods()[0];
      Member fetchedMethod = null;
      try { fetchedMethod = getMethodFromString( this.getClass().getName() + '#' + thisMethod.getName() + "#()V" ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getMethodString(): " + e.getMessage() ); }
      assertEquals("could not resolve method id string", thisMethod, fetchedMethod);

      // try to get a method from a not yet loaded class
      try { getMethodFromString( "ch.ethz.prose.HotSwapTest$MyDummy#publicMethod#()I" ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getMethodString() for a not loaded class: " + e.getMessage() ); }
      // try to get a private method
      try { getMethodFromString( "ch.ethz.prose.HotSwapTest$MyDummy#privateMethod#()V" ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getMethodString() for a private method: " + e.getMessage() ); }
      // try to get a static method
      try { getMethodFromString( "ch.ethz.prose.HotSwapTest#suite#()Ljunit/framework/Test;#" ); }
      catch(Throwable e) { fail("exception " + e.getClass().getName() + " @getMethodString() for a static method: " + e.getMessage() ); }
    }

    /**
     * Tests {@link ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl#getMethodFromString
     * getMethodFromString(java.lang.String)}.
     *
     */
    void testGetFieldFromString() {
      // do some calls with invalid parameters
      int catcheExceptions = 0;
      try{
        try{ getFieldFromString(null, true); }
        catch(NullPointerException e) { catcheExceptions++; }
        try{ getFieldFromString("class", false); }
        catch(InvalidIdException e) { catcheExceptions++; }
        try{ getFieldFromString("class#field", true); }
        catch(InvalidIdException e) { catcheExceptions++; }
        try{ getFieldFromString("class#method#I", false); }
        catch(ClassNotFoundException e) { catcheExceptions++; }
        try{ getFieldFromString(this.getClass().getName() + "#field#I", false); }
        catch(NoSuchFieldError e) { catcheExceptions++; }
        try{ getFieldFromString(this.getClass().getName() + "#dummy#Z", true); }
        catch(NoSuchFieldError e) { catcheExceptions++; }
      } catch(Exception e) { fail("throws wrong assertion" + e.getClass().getName()); }
      assertEquals("number of catched assertions", 6, catcheExceptions);

      // try to get 'dummy'.
      java.lang.reflect.Field thisField = this.getClass().getDeclaredFields()[0];
      java.lang.reflect.Field fetchedField = null;
      try { fetchedField = getFieldFromString( this.getClass().getName() + "#dummy#I", false ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getFieldString(): " + e.getMessage() ); }
      assertEquals("could not resolve field id string", thisField, fetchedField);

      // try to get a field from a not yet loaded class
      try { getFieldFromString( "ch.ethz.prose.HotSwapTest$MyDummy2#publicField#I", false ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getFieldString() for a not loaded class: " + e.getMessage() ); }
      // try to get a private field
      try { getFieldFromString( "ch.ethz.prose.HotSwapTest$MyDummy2#privateField#I", false ); }
      catch(Exception e) { fail("exception " + e.getClass().getName() + " @getFieldString() for a private field: " + e.getMessage() ); }
      // try to get a static field
      try { getFieldFromString( "ch.ethz.prose.HotSwapTest#staticField#I", true ); }
      catch(Throwable e) { fail("exception " + e.getClass().getName() + " @getFieldString() for a static field: " + e.getMessage() ); }
    }

    /**
     * Tests {@link ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl#getBCELClassDefinition
     * getBCELClassDefinition(java.lang.Class)}.
     */
    void testGetBCELClassDefinition() {
      int exceptionCount = 0;
      try {
        try{ getBCELClassDefinition( null ); }
        catch(NullPointerException e) { exceptionCount++; }
        // cannot test for NotInitializedException here, because once initialized,
        // it's not possible to uninitialize the  aspectInterface any more
        // except by forced unloading of the class (this was done to be compatible
        // with the debugging implementation of prose).
      } catch(Exception e) { fail("wrong exception type"); }
      assertEquals( "exception test", 1, exceptionCount );

      Class thisClass = this.getClass();
      JavaClass jc = null;
      try{ jc = getBCELClassDefinition( this.getClass() ); }
      catch(ClassNotFoundException e) { fail("class not found"); }

      // class name
      assertEquals("different class name", thisClass.getName(), jc.getClassName() );

      // access flags. Note: the ACC_SUPER flag (0x020 or 32) may be set in class files
      // but newer VMs ignores it and wont return it, when quering the flags with the
      // reflection API.
      int accessMask = 0x0611// no ACC_SUPER flag, which is ignored by newer JVMs
      int jvmAccessFlags = thisClass.getModifiers();
      int bcelAccessFlags = jc.getModifiers();
      assertEquals("different modifier (access flags)", jvmAccessFlags & accessMask, bcelAccessFlags & accessMask );

      // methods
      java.lang.reflect.Method[] methods = thisClass.getDeclaredMethods();
      for( int i = 0; i < methods.length; i++ ) {
        java.lang.reflect.Method method = methods[i];
        assertNotNull("class file has no definition for " + method.getName(), jc.getMethod( method ) );
      }
    }

    void testRedefineClass() { }

    void testRedefineClasses() { }

  }

  interface TestRedefineClasses {
    public int method();
  }

  class TestRedefineClasses1 {
    public int method() { return 1; }
    //  static public int statMethod() { return 1; }
  }

  class TestRedefineClasses2 {
    public int method() { return 2; }
    //  static public int StatMethod() { return 2; }
  }


  //--------------------------------------------------------------------------------------------------------------------------------------------

  /**
   * Construct test with given name.
   * @param name test name
   */
  public HotSwapTest(String name) {
    super(name);
  }

  /**
   * Set up fixture.
   */
  protected void setUp() {
    //  String providerClassName = System.getProperty("ch.ethz.prose.JVMAIProvider","ch.ethz.inf.iks.jvmai.jvmdi.HotSwapProvider");
    //  Class providerClass = Class.forName(providerClassName);
    //  Provider provider = (Provider)providerClass.newInstance();
    Provider provider = new HotSwapProvider();
    aspectInterface = (HotSwapAspectInterfaceImpl) provider.getAspectInterface();
    aspectInterface.startup(new String[0], true);
  }

  protected void teardown() {
    aspectInterface.teardown();
  }

  public void test_010_AspectInterface() {
    MyAspectInterface ai = new MyAspectInterface();
    ai.startup( new String[0], true );

    ai.testGetMethodFromString();
    ai.testGetBCELClassDefinition();

    ai.teardown();
  }

  public void test_020_RedefineClasses() {
    Class cl1=null, cl2=null;
    //   InputStream is1=null, is2=null;//, is3=null, is4=null;
    JavaClass jc1 = null, jc2 = null;

    // get classes
    try {
      cl1 = Class.forName( this.getClass().getName() + "$TestRedefineClasses1" );
      cl2 = Class.forName( this.getClass().getName() + "$TestRedefineClasses2" );
    }
    catch ( ClassNotFoundException nfe ) {
      fail( "Class not found: " + nfe.getMessage() + " (internal error in the test case)" );
    }
    Class[] cls1 = { cl1 };
    Class[] cls2 = { cl2 };

    // Check if could get unmodified class definitions (contents of class files)
    try { jc1 = HotSwapAspectInterfaceImpl.getBCELClassDefinition( cl1 ); }
    catch( ClassNotFoundException ie ) { fail( "getOriginalClassDefinition could not read class file (IOException)" ); }
    catch( Exception fe ) { fail( "getOriginalClassDefinition malformed class file" ); }

    /*
     // full verification
      Verifier veri1 = VerifierFactory.getVerifier("ch.ethz.prose.JVMAspectInterfaceTest$TestRedefineClasses2");
      VerificationResult vr1 = veri1.doPass1();
      assertEquals( VerificationResult.VERIFIED_OK, vr1.getStatus() );
      VerificationResult vr2 = veri1.doPass2();
      assertEquals( VerificationResult.VERIFIED_OK, vr2.getStatus() );
      VerificationResult vr3a = veri1.doPass3a(1);
      assertEquals( VerificationResult.VERIFIED_OK, vr3a.getStatus() );
      VerificationResult vr3b = veri1.doPass3b(1);
      assertEquals( VerificationResult.VERIFIED_OK, vr3b.getStatus() );
     */

    try { jc2 = HotSwapAspectInterfaceImpl.getBCELClassDefinition( cl2 ); }
    catch( ClassNotFoundException ie ) { fail( "getClassDefinition could not read unmodified class file (IOException)" ); }
    catch( Exception fe ) { fail( "getClassDefinition malformed unmodified class file" ); }

    // test original methods
    TestRedefineClasses1 test1 = new TestRedefineClasses1();
    assertEquals( "unmodified test1.method() failed (internal error in the test)", 1, test1.method() );

    //
    // Redefine cl1 using cl2
    //

    // change the behavour of cl1
    ClassGen cgen = new ClassGen( jc1 );
    ConstantPoolGen cpgen = cgen.getConstantPool();
    org.apache.bcel.classfile.Method meth = cgen.getMethodAt( 1 );
    MethodGen mgen = new MethodGen( meth, cgen.getClassName(), cpgen );
    cgen.removeMethod( meth );
    InstructionList il = mgen.getInstructionList();
    InstructionHandle ih = il.findHandle( 0 );
    Instruction in = new ICONST( 2 );
    ih.setInstruction( in );
    cgen.addMethod( mgen.getMethod() );
    il.dispose();

    byte[] klassDef = cgen.getJavaClass().getBytes();
    byte[][] defs = { klassDef };


    // redefine cls1 using cls2
    try { HotSwapClassWeaver.redefineClasses( cls1, defs ); }
    catch ( RuntimeException re ) { fail( "redefineClasses could not redefine class (RuntimeException) " + re.getMessage() ); }

    // test replaced methods
    assertEquals( "redefineClasses modified test1.method() failed", 2, test1.method() );
  }

  /**
   * Test suite.
   * @return test instance
   */
  public static Test suite() {
    return new TestSuite(HotSwapTest.class);
  }

}
TOP

Related Classes of ch.ethz.prose.HotSwapTest$TestRedefineClasses

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.