Package ch.ethz.inf.iks.jvmai.jvmdi

Source Code of ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl

//
//  This file is part of the prose package.
//
//  The contents of this file are subject to the Mozilla Public License
//  Version 1.1 (the "License"); you may not use this file except in
//  compliance with the License. You may obtain a copy of the License at
//  http://www.mozilla.org/MPL/
//
//  Software distributed under the License is distributed on an "AS IS" basis,
//  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
//  for the specific language governing rights and limitations under the
//  License.
//
//  The Original Code is prose.
//
//  The Initial Developer of the Original Code is Angela Nicoara. Portions
//  created by Angela Nicoara are Copyright (C) 2004 Angela Nicoara.
//  All Rights Reserved.
//
//  Contributor(s):
//  $Id: HotSwapAspectInterfaceImpl.java,v 1.2 2008/11/18 11:09:31 anicoara Exp $
//  ==============================================================================
//

package ch.ethz.inf.iks.jvmai.jvmdi;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.lang.reflect.*;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;

import ch.ethz.jvmai.*;

/**
* HotSwapAspectInterfaceImpl class.
*
* @author  Angela Nicoara
* @author  Gerald Linhofer
* @version $Revision: 1.2 $
*/
public class HotSwapAspectInterfaceImpl extends AspectInterfaceImpl {

  /**
   * Gathers and holds informations about field and method call join points
   */
  protected static HotSwapClassRegister classRegister  = null;
  /**
   * Caches class definitions, which where fetched by {@link #getOriginalClassDefinition}
   * @deprecated
   */
  protected static CacheMap classFileMap        = null;

  /**
   * Caches reflected Method objects resolved by
   * the <CODE>getMethodFromString()</CODE> methods.
   */
  protected static CacheMap resolvedMethods      = null;
  /**
   * Caches reflected Field objects resolved by
   * the <CODE>getFieldFromString()</CODE> methods.
   */
  protected static CacheMap resolvedFields      = null;
  //
  // Arrays holding the tags for active advices, tags will be
  // added by the set..Watch(), removed by
  // clear...Watch() and used in doOn...() methods.
  //
  protected static Object methodEntryTags[]       = null;
  protected static Object methodExitTags[]       = null;
  protected static Object constructorTags[]      = null;
  // protected static Object methodCallTags[]      = null;
  // protected static Object methodReturnTags[]    = null;
  protected static Object fieldAccessTags[]       = null;
  protected static Object fieldModificationTags[]   = null;

  /**
   * <CODE>true</CODE> if HotSwapAspectInterfaceImpl was initialized.
   */
  protected static boolean initialized = false;

  /**
   * Replacement tag, will be used as tag, if the user supplied tag
   * is <CODE>null</CODE>. (Required to store the tag in data
   * structures that didn't allow <CODE>null</CODE> entries.)
   */
  protected static Object aopNullTag = new Object();

  //
  // Join point objects for the various join points, the objects are preallocated
  // and will be reused at each advice call from the same join point type.
  // (Dont forget to SYNCHRONIZE uses of these objects!!!)
  //
  protected static HotSwapMethodEntryJoinPointImpl   methodEntryJoinPoint = new HotSwapMethodEntryJoinPointImpl();
  protected static HotSwapMethodExitJoinPointImpl   methodExitJoinPoint = new HotSwapMethodExitJoinPointImpl();
  protected static HotSwapConstructorJoinPointImpl  constructorJoinPoint = new HotSwapConstructorJoinPointImpl();
  protected static HotSwapFieldAccessJoinPointImpl  fieldAccessJoinPoint = new HotSwapFieldAccessJoinPointImpl();
  protected static HotSwapFieldModificationJoinPointImpl   fieldModificationJoinPoint = new HotSwapFieldModificationJoinPointImpl();

  //
  // Holds threads that will be ignored, if they call a doOn...() callback method.
  // Used during advice weaving to supress notifications.
  //
  protected static Set suspendedThreads = new HashSet(1024);
  //  protected static Set<Thread> suspendedThreads = new HashSet<Thread>(1024);  // only JDK 1.5 or above

  // Class loader used by 'get*ClassDefinition' and 'getMethodFromString'.
  private static ClassLoader contingencyLoader  = null;

  // holds the instance of HotSwapAspectInteface (Singelton Pattern) 
  private static HotSwapAspectInterfaceImpl instance;

  /**
   * Constructor. Dont call it, use {@link HotSwapAspectInterfaceImpl#getInstance
   * getInstance()} to create an instance of this class.
   * <P>
   * This is not private to allow unit testing.
   */
  protected HotSwapAspectInterfaceImpl() {}

  /**
   * Returns the instance of HotSwapAspectInterfaceImpl and creates it
   * if required. There's only one instance of this class (Singelton Pattern).
   *
   * @return HotSwapAspectInterfaceImpl instance
   */
  public static HotSwapAspectInterfaceImpl getInstance() {
    if( null == instance )
      instance = new HotSwapAspectInterfaceImpl();
    return instance;
  }

  //------------------------------------------------------------------------------------------------------------------
  // Interface for the JoinPointManager
  //------------------------------------------------------------------------------------------------------------------

  /**
   * Initializes the underlying jvmai system.
   * <p>
   * In addition, this method takes a list of java package-names and a
   * boolean indicating how to interpret this prefixes. The prefixes are
   * used by the jvmai system to determine the set of classes beeing
   * relevant to the system at all.
   * Depeding on the value of <code>openWorldAssumption</code>, prefixes
   * are interpreted as followed:
   * <p>
   * <code>openWorldAssumption == true</code><br>
   * The jvmai-system is instructed to treat ALL classes as relevant,
   * EXCEPT the ones contained in a packages starting with one of the
   * supplied prefixes in <code>packagePrefixes</code>
   * <p>
   * <code>openWorldAssumption == false</code><br>
   * The jvmai-system is instructed to treat as relevant ONLY the classes
   * contained in a packages starting with one of the supplied prefixes
   * in <code>packagePrefixes</code>
   *
   * @param packagePrefixes List of prefixes for java package-names.
   * @param openWorldAssumption Specifies how the prefixes are interpreted.
   * @exception StartupException Use <code>StartupException.getMessage()</code> to get a detailed description
   */
  public synchronized void startup(String[] packagePrefixes, boolean openWorldAssumption) {
    if(null == packagePrefixes)
      packagePrefixes = new String[0];

    // make sure all classes that are addressed during event notification are loaded already here
    Class toload;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.JumpFinallyVisitor.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapProvider.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapMethodEntryJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapMethodExitJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldAccessJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldModificationJoinPointImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapSignatureImpl.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassRegister.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldWeaver.class;
    toload=ch.ethz.inf.iks.jvmai.jvmdi.CacheMap.class;
    toload=ch.ethz.jvmai.MethodRedefineJoinPoint.class;
    toload=ch.ethz.jvmai.UnmodifiableClassException.class;
    toload=ch.ethz.jvmai.IlligalClassFormatException.class;
    // BCEL classes must be loaded at startup to prevent
    // dead locks, if BCEL is used to parse classes on class
    // load.
    toload=org.apache.bcel.Constants.class;
    toload=org.apache.bcel.classfile.AccessFlags.class;
    toload=org.apache.bcel.classfile.Attribute.class;
    toload=org.apache.bcel.classfile.ClassParser.class;
    toload=org.apache.bcel.classfile.JavaClass.class;
    toload=org.apache.bcel.classfile.FieldOrMethod.class;
    toload=org.apache.bcel.classfile.Method.class;
    toload=org.apache.bcel.classfile.Field.class;
    toload=org.apache.bcel.classfile.Code.class;
    toload=org.apache.bcel.classfile.Constant.class;
    toload=org.apache.bcel.classfile.ConstantCP.class;
    toload=org.apache.bcel.classfile.ConstantDouble.class;
    toload=org.apache.bcel.classfile.ConstantFieldref.class;
    toload=org.apache.bcel.classfile.ConstantFloat.class;
    toload=org.apache.bcel.classfile.ConstantInteger.class;
    toload=org.apache.bcel.classfile.ConstantInterfaceMethodref.class;
    toload=org.apache.bcel.classfile.ConstantMethodref.class;
    toload=org.apache.bcel.classfile.ConstantNameAndType.class;
    toload=org.apache.bcel.classfile.ConstantString.class;
    toload=org.apache.bcel.classfile.ConstantUtf8.class;
    toload=org.apache.bcel.classfile.ConstantClass.class;
    toload=org.apache.bcel.classfile.ConstantValue.class;
    toload=org.apache.bcel.classfile.ConstantPool.class;
    toload=org.apache.bcel.classfile.InnerClass.class;
    toload=org.apache.bcel.classfile.InnerClasses.class;
    toload=org.apache.bcel.classfile.ExceptionTable.class;
    toload=org.apache.bcel.classfile.LineNumber.class;
    toload=org.apache.bcel.classfile.LineNumberTable.class;
    toload=org.apache.bcel.classfile.LocalVariable.class;
    toload=org.apache.bcel.classfile.LocalVariableTable.class;
    toload=org.apache.bcel.classfile.StackMapEntry.class;
    toload=org.apache.bcel.classfile.StackMapType.class;
    toload=org.apache.bcel.classfile.StackMap.class;
    toload=org.apache.bcel.classfile.Signature.class;
    toload=org.apache.bcel.classfile.SourceFile.class;
    toload=org.apache.bcel.classfile.Synthetic.class;
    toload=org.apache.bcel.classfile.Deprecated.class;
    toload=org.apache.bcel.classfile.Utility.class;
    toload=org.apache.bcel.generic.AALOAD.class;
    toload=org.apache.bcel.generic.AASTORE.class;
    toload=org.apache.bcel.generic.ACONST_NULL.class;
    toload=org.apache.bcel.generic.ALOAD.class;
    toload=org.apache.bcel.generic.ANEWARRAY.class;
    toload=org.apache.bcel.generic.ARETURN.class;
    toload=org.apache.bcel.generic.ArithmeticInstruction.class;
    toload=org.apache.bcel.generic.ArrayInstruction.class;
    toload=org.apache.bcel.generic.ARRAYLENGTH.class;
    toload=org.apache.bcel.generic.ArrayType.class;
    toload=org.apache.bcel.generic.ALOAD.class;
    toload=org.apache.bcel.generic.ASTORE.class;
    toload=org.apache.bcel.generic.BALOAD.class;
    toload=org.apache.bcel.generic.BasicType.class;
    toload=org.apache.bcel.generic.BASTORE.class;
    toload=org.apache.bcel.generic.BIPUSH.class;
    toload=org.apache.bcel.generic.BranchHandle.class;
    toload=org.apache.bcel.generic.BranchInstruction.class;
    toload=org.apache.bcel.generic.BREAKPOINT.class;
    toload=org.apache.bcel.generic.CALOAD.class;
    toload=org.apache.bcel.generic.CASTORE.class;
    toload=org.apache.bcel.generic.CHECKCAST.class;
    toload=org.apache.bcel.generic.ClassGen.class;
    toload=org.apache.bcel.generic.CodeExceptionGen.class;
    toload=org.apache.bcel.generic.ConstantPoolGen.class;
    toload=org.apache.bcel.generic.ConversionInstruction.class;
    toload=org.apache.bcel.generic.CPInstruction.class;
    toload=org.apache.bcel.generic.D2F.class;
    toload=org.apache.bcel.generic.D2I.class;
    toload=org.apache.bcel.generic.D2L.class;
    toload=org.apache.bcel.generic.DADD.class;
    toload=org.apache.bcel.generic.DALOAD.class;
    toload=org.apache.bcel.generic.DASTORE.class;
    toload=org.apache.bcel.generic.DCMPG.class;
    toload=org.apache.bcel.generic.DCMPL.class;
    toload=org.apache.bcel.generic.DCONST.class;
    toload=org.apache.bcel.generic.DDIV.class;
    toload=org.apache.bcel.generic.DLOAD.class;
    toload=org.apache.bcel.generic.DMUL.class;
    toload=org.apache.bcel.generic.DNEG.class;
    toload=org.apache.bcel.generic.DREM.class;
    toload=org.apache.bcel.generic.DRETURN.class;
    toload=org.apache.bcel.generic.DSTORE.class;
    toload=org.apache.bcel.generic.DSUB.class;
    toload=org.apache.bcel.generic.DUP.class;
    toload=org.apache.bcel.generic.DUP_X1.class;
    toload=org.apache.bcel.generic.DUP_X2.class;
    toload=org.apache.bcel.generic.DUP2.class;
    toload=org.apache.bcel.generic.DUP2_X1.class;
    toload=org.apache.bcel.generic.DUP2_X2.class;
    toload=org.apache.bcel.generic.F2D.class;
    toload=org.apache.bcel.generic.F2I.class;
    toload=org.apache.bcel.generic.F2L.class;
    toload=org.apache.bcel.generic.FADD.class;
    toload=org.apache.bcel.generic.FALOAD.class;
    toload=org.apache.bcel.generic.FASTORE.class;
    toload=org.apache.bcel.generic.FCMPG.class;
    toload=org.apache.bcel.generic.FCMPL.class;
    toload=org.apache.bcel.generic.FCONST.class;
    toload=org.apache.bcel.generic.FDIV.class;
    toload=org.apache.bcel.generic.FieldGen.class;
    toload=org.apache.bcel.generic.FieldGenOrMethodGen.class;
    toload=org.apache.bcel.generic.FieldInstruction.class;
    toload=org.apache.bcel.generic.FieldOrMethod.class;
    toload=org.apache.bcel.generic.FLOAD.class;
    toload=org.apache.bcel.generic.FMUL.class;
    toload=org.apache.bcel.generic.FNEG.class;
    toload=org.apache.bcel.generic.FREM.class;
    toload=org.apache.bcel.generic.FRETURN.class;
    toload=org.apache.bcel.generic.FSTORE.class;
    toload=org.apache.bcel.generic.FSUB.class;
    toload=org.apache.bcel.generic.GETFIELD.class;
    toload=org.apache.bcel.generic.GETSTATIC.class;
    toload=org.apache.bcel.generic.GOTO.class;
    toload=org.apache.bcel.generic.GOTO_W.class;
    toload=org.apache.bcel.generic.GotoInstruction.class;
    toload=org.apache.bcel.generic.I2B.class;
    toload=org.apache.bcel.generic.I2C.class;
    toload=org.apache.bcel.generic.I2D.class;
    toload=org.apache.bcel.generic.I2F.class;
    toload=org.apache.bcel.generic.I2L.class;
    toload=org.apache.bcel.generic.I2S.class;
    toload=org.apache.bcel.generic.IADD.class;
    toload=org.apache.bcel.generic.IALOAD.class;
    toload=org.apache.bcel.generic.IAND.class;
    toload=org.apache.bcel.generic.IASTORE.class;

    super.startup( packagePrefixes, openWorldAssumption );

    if(initialized)
      return;

    // initialize static fields
    methodEntryTags     = new Object[1024];
    methodExitTags       = new Object[1024];
    constructorTags      = new Object[1024];
    fieldAccessTags       = new Object[1024];
    fieldModificationTags   = new Object[1024];
    //    methodCallTags      = new Object[1024];
    //    methodReturnTags    = new Object[1024];

    doStartUp( packagePrefixes, openWorldAssumption );


    if (contingencyLoader == null)  {
      Iterator i = getLoadedClasses().iterator();
      while(i.hasNext() && contingencyLoader == null) {
        Class cls=(Class)i.next();
        contingencyLoader=cls.getClassLoader();
      }
      classFileMap = new CacheMap( 1024 );
      resolvedMethods = new CacheMap( 1024 );
      resolvedFields = new CacheMap( 1024 );
      classRegister = HotSwapClassRegister.getInstance();
    }

    initialized = true;

    HotSwapClassWeaver.setAspectInterface( this );
    HotSwapClassRegister.setAspectInterface( this, packagePrefixes, openWorldAssumption );
  }

  /**
   *  Teardown the AOP support. As a result,
   *  no events will be sent to the JoinPointHook.
   */
  public synchronized void teardown() {
    super.teardown();

    // static members
    initialized       = false;
    hook           = null;
    methodEntryTags      = null;
    methodExitTags       = null;
    constructorTags      = null;
    fieldAccessTags       = null;
    fieldModificationTags   = null;
    //    methodCallTags      = null;
    //    methodReturnTags    = null;

    suspendedThreads.clear();
    classFileMap.clear();
    resolvedMethods.clear();
    resolvedFields.clear();

    classRegister.reset();
  }

  /**
   * Sets a watch on a method entry joinpoint.
   *
   * @param m the method to be watched.
   * @param aopTag A user-defined object saved with this watch.
   *               When the joinpoint is reached, this object is
   *               passed to the JoinPointHook as part of the
   *               JoinPoint-instance. This object may be <code>null</code>.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception CannotSetWatchException The method must not be abstract or native.
   * @exception WatchAlreadySetException There already exists a entry-watch on the method.
   */
  public void setMethodEntryWatch(Method m, Object aopTag) {
    // check preconditions
    checkWatchPrecondition(m,aopTag);

    if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
      throw new CannotSetWatchException("HotSwapAspectInterfaceImpl.setMethodEntryWatch: cannot set watches on interfaces");

    synchronized(methodEntryTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver( m );
      methodEntryTags = setWatch( methodEntryTags, aopTag, mw.getTargetId() );   
      mw.setMethodEntryEnabled( true );
    }
  }

  /**
   * Clears a watch on a method entry joinpoint.
   *
   * @param m the method beeing watched.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception WatchNotSetException There exists no entry-watch on the method.
   */
  public synchronized void clearMethodEntryWatch(Method m) {
    // preconditions
    if (!initialized)
      throw new NotInitializedException();
    if (m == null)
      throw new NullPointerException("Parameter `m' must not be null.");
    if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
      throw new CannotSetWatchException("HotSwapAspectInterfaceImpl.clearMethodEntryWatch: cannot clear watches on interfaces");

    //System.out.println("HotSwapAspectInterfaceImpl.clearMethodEntryWatch(): " + m);
    synchronized(methodEntryTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
      clearWatch( methodEntryTags, mw.getTargetId() );
      mw.setMethodEntryEnabled(false);
    }
  }


  /**
   * Sets a watch on a method exit joinpoint.
   *
   * @param m the method to be watched.
   * @param aopTag A user-defined object saved with this watch.
   *               When the joinpoint is reached, this object is
   *               passed to the JoinPointHook as part of the
   *               JoinPoint-instance. This object may be <code>null</code>.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception CannotSetWatchException The method must not be abstract or native.
   * @exception WatchAlreadySetException There already exists a exit-watch on the method.
   */
  public synchronized void setMethodExitWatch(Method m, Object aopTag) {
    // preconditions
    checkWatchPrecondition(m,aopTag);
    if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
      throw new CannotSetWatchException("Method is abstract: " + m);

    //System.out.println("HotSwapAspectInterfaceImpl.setMethodExitWatch(): " + m);
    synchronized(methodExitTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
      methodExitTags = setWatch(methodExitTags, aopTag, mw.getTargetId());
      mw.setMethodExitEnabled(true);
    }
  }

  /**
   * Clears a watch on a method exit joinpoint.
   *
   * @param m the method beeing watched.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception WatchNotSetException There exists no exit-watch on the method.
   */
  public void clearMethodExitWatch(Method m) {
    // preconditions
    if (!initialized)
      throw new NotInitializedException();
    if (m == null)
      throw new NullPointerException("Parameter `m' must not be null.");
    if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
      throw new CannotSetWatchException("Method is abstract: " + m);

    //System.out.println("HotSwapAspectInterfaceImpl.clearMethodEntryWatch(): " + m);
    synchronized(methodExitTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
      clearWatch(methodExitTags, mw.getTargetId());
      mw.setMethodExitEnabled(false);
    }
  }

  /**
   * Sets a watch on a constructor joinpoint.
   *
   * @param m the constructor to be watched.
   * @param aopTag A user-defined object saved with this watch.
   *               When the joinpoint is reached, this object is
   *               passed to the JoinPointHook as part of the
   *               JoinPoint-instance. This object may be <code>null</code>.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception CannotSetWatchException The method must not be abstract or native.
   * @exception WatchAlreadySetException There already exists a entry-watch on the method.
   */
  public void setConstructorWatch(Constructor m, Object aopTag) {
    // check preconditions
    checkWatchPrecondition(m,aopTag);

    if ((m.getModifiers() & Modifier.ABSTRACT ) != 0)
      throw new CannotSetWatchException("HotSwapAspectInterfaceImpl.setConstructorWatch: cannot set watches on interfaces");

    synchronized(constructorTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver( m );
      constructorTags = setWatch( constructorTags, aopTag, mw.getTargetId() );
      // TODO: change to something like constructor enabled   
      mw.setMethodEntryEnabled( true );
    }
  }

  /**
   * Clears a watch on a constructor joinpoint.
   *
   * @param m the constructor beeing watched.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
   * @exception WatchNotSetException There exists no entry-watch on the method.
   */
  public synchronized void clearConstructorWatch(Constructor m) {
    // preconditions
    if (!initialized)
      throw new NotInitializedException();
    if (m == null)
      throw new NullPointerException("Parameter `m' must not be null.");
    if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
      throw new CannotSetWatchException("HotSwapAspectInterfaceImpl.clearConstructorWatch: cannot clear watches on interfaces");

    //System.out.println("HotSwapAspectInterfaceImpl.clearConstructorWatch(): " + m);
    synchronized(constructorTags) {
      MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
      clearWatch( constructorTags, mw.getTargetId() );
      // TODO: change to something like constructor enabled
      mw.setMethodEntryEnabled(false);
    }
  }


  /**
   * Sets a watch on a field access joinpoint.
   *
   * @param field the field to be watched.
   * @param aopTag A user-defined object saved with this watch.
   *               When the joinpoint is reached, this object is
   *               passed to the JoinPointHook as part of the
   *               JoinPoint-instance. This object may be <code>null</code>.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
   * @exception CannotSetWatchException ?
   * @exception WatchAlreadySetException There already exists a access-watch on the field.
   */
  public void setFieldAccessWatch(Field field, Object aopTag) {
    // check preconditions
    checkWatchPrecondition(field,aopTag);

    synchronized(fieldAccessTags) {
      HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver( field );
      fieldAccessTags = setWatch( fieldAccessTags, aopTag, fw.getTargetId() );
      fw.setFieldAccessEnabled( true );
    }
  }

  /**
   * Clears a watch on a field access joinpoint.
   *
   * @param field the field beeing watched.
   * @exception NotInitializedException Aspect-interface has not been intialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
   * @exception WatchNotSetException There exists no access-watch on the field.
   */
  public void clearFieldAccessWatch(Field field) {
    if (!isInitialized || !initialized)
      throw new NotInitializedException("HotSwapAspectInterfaceImpl.clearFieldAccessWatch: jvmai not initialized");
    if (field == null)
      throw new NullPointerException("HotSwapAspectInterfaceImpl.clearFieldAccessWatch: null cls parameter");

    synchronized(fieldAccessTags) { 
      HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver( field );
      clearWatch( fieldAccessTags, fw.getTargetId() );
      fw.setFieldAccessEnabled( false );
    }
  }

  /**
   * Sets a watch on a field modification joinpoint.
   *
   * @param field the field to be watched.
   * @param aopTag A user-defined object saved with this watch.
   *               When the joinpoint is reached, this object is
   *               passed to the JoinPointHook as part of the
   *               JoinPoint-instance. This object may be <code>null</code>.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exist no field with id <code>fieldId</code> in class <code>cls</code>.
   * @exception CannotSetWatchException ?
   * @exception WatchAlreadySetException There already exists a modification-watch on the field.
   */
  public void setFieldModificationWatch(Field field, Object aopTag) {
    //System.out.println("HotSwapAspectInterfaceImpl.setFieldModificationWatch() for " + field );
    // check preconditions
    checkWatchPrecondition(field,aopTag);

    synchronized( fieldModificationTags ) {   
      HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver( field );
      fieldModificationTags = setWatch( fieldModificationTags, aopTag, fw.getTargetId() );
      fw.setFieldModificationEnabled( true );
    }
  }

  /**
   * Clears a watch on a field modification joinpoint.
   *
   * @param field the field beeing watched.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>cls</code> is <code>null</code>.
   * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
   * @exception WatchNotSetException There exists no modification-watch on the field.
   */
  public void clearFieldModificationWatch(Field field) {
    if (!isInitialized || !initialized)
      throw new NotInitializedException("HotSwapAspectInterfaceImpl.clearFieldAccessWatch: jvmai not initialized");
    if (field == null)
      throw new NullPointerException("HotSwapAspectInterfaceImpl.clearFieldAccessWatch: null cls parameter");

    synchronized(fieldModificationTags) { 
      HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver( field );
      clearWatch( fieldModificationTags, fw.getTargetId() );
      fw.setFieldModificationEnabled( false );
    }
  }

  /**
   * Suspend notification regarding the specified thread.
   * Successive calls to <code>suspendNotification</code>
   * have to be balanced by (at least) the same number of calls to
   * <code>resumeNotification</code>, or the jvmai-system
   * will not resume notification.
   *
   * @param thread Thread for which to disable notification.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>thread</code> is <code>null</code>.
   */
  public void suspendNotification(Thread thread) {
    if (!initialized)
      throw new NotInitializedException();
    if (thread == null)
      throw new NullPointerException("Parameter `thread' must not be null");

    suspendedThreads.add(thread);

    super.suspendNotification( thread );
  }

  /**
   * Resumes notification regarding the specified thread.
   * Successive calls to <code>resumeNotification</code>
   * without preceding calls to <code>suspendNotification</code>
   * will be ignored by the jvmai-system.
   *
   * @param thread Thread for which to reenable notification.
   * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
   * @exception NullPointerException <code>thread</code> is <code>null</code>.
   */
  public void resumeNotification(Thread thread) {
    if (!initialized)
      throw new NotInitializedException();
    if (thread == null)
      throw new NullPointerException("Parameter `thread' must not be null");

    try {
      HotSwapFieldWeaver.commit();
      HotSwapClassWeaver.commit();
    }
    finally {
      suspendedThreads.remove(thread);
    }

    super.resumeNotification(thread);
  }

  /**
   * Check if the parameters are not null and if this object
   * was initialized. If not an exception will be thrown.
   *
   * @param arg
   * @param aopTag
   * @throws NotInitializedException this object was not initialized.
   * @throws NullPointerException <CODE>arg<CODE> is <CODE>null</CODE>.
   * @throws IlligalArgumentExceptin <CODE>aopTag</CODE> is <CODE>null</CODE>.
   */
  private void checkWatchPrecondition( Object arg, Object aopTag ) {
    if (!initialized)
      throw new NotInitializedException("HotSwapAspectInterfaceImpl.setWatch: jvmai not initialized");
    if (arg == null)
      throw new NullPointerException("HotSwapAspectInterfaceImpl.setWatch: null argument parameter");
    if (aopTag == null)
      throw new IllegalArgumentException("HotSwapAspectInterfaceImpl.setWatch: null aopTag value");
  }

  /**
   * Set `tags[id]' to `tag'. If `tags' is too small then resize it
   * appriopriately.
   *
   * @param tags array holding tags.
   * @param tag tag that should be inserted in <CODE>tags</CODE>.
   * @param id index at which <CODE>tag</CODE> should be inserted.
   * @return the new array for <CODE>tags</CODE>.
   */
  private Object[] setWatch(Object[] tags, Object tag, int id) {
    synchronized (tags) {
      if( tags.length < id ) {
        Object tmp[] = new Object[2 * id];
        System.arraycopy(tags, 0, tmp, 0, tags.length);
        tags = tmp;
      }
      if (tags[id] != null)
        throw new WatchAlreadySetException("<" + id + ">");
      tags[id] = (tag == null) ? aopNullTag : tag;
    }
    return tags;
  }

  /**
   * Set `tags[id] = null'. If `id' is out of bounds or the watch already
   * cleared a WatchNotSetException is thrown.
   *
   * @param tags AOP tag array
   * @param id Index into `tags'
   */
  private void clearWatch(Object[] tags, int id) {
    synchronized (tags) {
      try {
        if (tags[id] == null)
          throw new WatchNotSetException("<" + id + ">");
        tags[id] = null;
      } catch (ArrayIndexOutOfBoundsException e) {
        throw new WatchNotSetException("<" + id + ">");
      }
    }
  }




  //-----------------------------------------------------------------------------------------------------------------------------
  // Callback functions
  //-----------------------------------------------------------------------------------------------------------------------------

  /**
   * This callback will be invoked at method entry join points. Invocation only
   * takes place if the callback is woven in to the corresponding method.
   *
   * @param methodId method identifier
   */
  public static final void doOnMethodEntry( int methodId ) {
    Object aopTag = methodEntryTags[methodId];
    Thread currentThread = Thread.currentThread();

    if (hook == null || suspendedThreads.contains(currentThread) || null == aopTag)
      return;

    // Suspend this thread to prevent crosscutting of advice execution
    // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
    suspendedThreads.add(currentThread);

    try{
      // there's only one join point of this type, so it
      // must be synchronized.
      synchronized( methodEntryJoinPoint ) {
        methodEntryJoinPoint.init( methodId, aopTag );
        hook.onMethodEntry( methodEntryJoinPoint );
      }
    } finally {
      // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
      suspendedThreads.remove(currentThread);
    }
    // TODO: benchmark if it's faster to generate a new join point object
    //hook.onMethodEntry( new HotSwapMethodEntryJoinPointImpl( methodId, aopTag) );
  }

  /**
   * This callback will be invoked at method exit join points. Invocation only
   * takes place if the callback is woven in to the corresponding method.
   *
   * @param methodId method identifier
   * @param resultSlot index of the result in the local variable table
   */
  public static final void doOnMethodExit(int methodId, int resultSlot) {
    Object aopTag = methodExitTags[methodId];
    Thread currentThread = Thread.currentThread();

    if (hook == null || suspendedThreads.contains(currentThread) || null == aopTag)
      return;

    // Suspend this thread to prevent crosscutting of advice execution
    // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
    suspendedThreads.add(currentThread);

    try {
      // there's only one join point of this type, so it
      // must be synchronized.
      synchronized( methodExitJoinPoint ) {
        methodExitJoinPoint.init( methodId, aopTag, resultSlot );
        hook.onMethodExit( methodExitJoinPoint );
      }
    } finally {
      // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
      suspendedThreads.remove(currentThread);
    }

    // TODO: benchmark if it's faster to generate a new join point object
    //hook.onMethodExit( new HotSwapMethodEntryJoinPointImpl( methodId, aopTag, resultSlot ) );
  }

  /**
   * This callback will be invoked at constructor join points. Invocation only
   * takes place if the callback is woven in to the corresponding constructor.
   *
   * @param methodId method identifier
   */
  public static final void doOnConstructor(/*Object this0,*/ int methodId) {
    Object aopTag = constructorTags[methodId];
    Thread currentThread = Thread.currentThread();

    if (hook == null || suspendedThreads.contains(currentThread) || null == aopTag)
      return;

    // Suspend this thread to prevent crosscutting of advice execution
    // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
    suspendedThreads.add(currentThread);

    try {
      // there's only one join point of this type, so it
      // must be synchronized.
      synchronized( constructorJoinPoint ) {
        constructorJoinPoint.init( null /*this0*/, methodId, aopTag );
        hook.onConstructor( constructorJoinPoint );
      }
    } finally {
      // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
      suspendedThreads.remove(currentThread);
    }

    // TODO: benchmark if it's faster to generate a new join point object
    //hook.onConstructor( new HotSwapMethodEntryJoinPointImpl( this0, methodId, aopTag) );
  }

  /**
   * This callback will be invoked at field access join points. Invocation only
   * takes place if the callback is woven in to the corresponding method.
   *
   * @param owner object that contains the field
   * @param fieldId field identifier
   */
  public static final void doOnFieldAccess(Object owner, int fieldId ) {
    //System.out.println("HotSwapAspectInterfaceImpl.doOnFieldAccess(" + owner + "," + fieldId + ")");
    Object aopTag = fieldAccessTags[fieldId];
    Thread currentThread = Thread.currentThread();

    if (hook == null || suspendedThreads.contains(currentThread) || null == aopTag)
      return;

    // Suspend this thread to prevent crosscutting of advice execution
    // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
    suspendedThreads.add(currentThread);

    try {
      // there's only one join point of this type, so it
      // must be synchronized.
      synchronized( fieldAccessJoinPoint ) {
        fieldAccessJoinPoint.init( aopTag, fieldId, owner);
        hook.onFieldAccess(fieldAccessJoinPoint);
      }
    } finally {
      // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
      suspendedThreads.remove(currentThread);
   

    // TODO: benchmark if it's faster to generate a new join point object
    //hook.onFieldAccess( new HotSwapMethodEntryJoinPointImpl( aopTag, fieldId, owner ) );
  }

  /**
   * This callback will be invoked at field modification join points. Invocation only
   * takes place if the callback is woven in to the corresponding method.
   *
   * @param owner object that contains the field
   * @param fieldId field identifier
   * @param slot index of the local variable that contains the new value for the field
   */
  public static final void doOnFieldModification( Object owner, int fieldId, int slot ) {
    //System.out.println("HotSwapAspectInterfaceImpl.doOnFieldModification(" + owner + "," + fieldId + "," + slot + ")");
    Object aopTag = fieldModificationTags[fieldId];
    Thread currentThread = Thread.currentThread();

    if (hook == null || suspendedThreads.contains(currentThread) || null == aopTag)
      return;

    // Suspend this thread to prevent crosscutting of advice execution
    // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
    suspendedThreads.add(currentThread);

    try {
      // there's only one join point of this type, so it
      // must be synchronized.
      synchronized( fieldModificationJoinPoint ) {
        fieldModificationJoinPoint.init( aopTag, slot, fieldId, owner);
        hook.onFieldModification(fieldModificationJoinPoint);
      }
    } finally {
      // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
      suspendedThreads.remove(currentThread);
    }

    // TODO: benchmark if it's faster to generate a new join point object
    //hook.onFieldModification( new HotSwapMethodEntryJoinPointImpl( aopTag, slot, fieldId, owner ) );
  }

  /**
   * Called when ever a new class is loaded by the VM.
   * @param cls the new class.
   */
  //public static void doOnClassLoad( Class cls ) {  //BEFORE - delete
  protected void doOnClassLoad( Class cls ) {      //CORECT - BUGFIX ANGY/GERY - both methods (from AspectInterfaceImpl and HotswapAspectInterfaceImpl) need to have the same modifiers = have to be PROTECTED
    if( null != hook ) {
      // 1. Notify JoinPointManager
      hook.onClassLoad( cls );
    }
    // 2. Notify HotSwapClassRegister (scanns the class if required)
    // may also trigger weaving.
    classRegister.classLoaded( cls );
  }

  /**
   * Called when ever the VM unloads a class.
   * This works only with JVMDI, JVMTI has no
   * support for unload events.
   *
   * @param cls
   */
  public static void doOnClassUnload( Class cls ) {
    if( null == classRepository )
      return;

    // Remove from class file repository.
    JavaClass bcelClass = classRepository.findClass( cls.getName() );
    if( null != bcelClass )
      classRepository.removeClass( bcelClass );
    // Notify HotSwapClassRegister
    //HotSwapClassRegister.getInstance().classUnloaded( cls ); 
  }

  //------------------------------------------------------------------------------
  // Utility functions
  //------------------------------------------------------------------------------

  /**
   * Returns the reflected Method, for a id string containing the class name,
   * the method name and it's signature, separated by '#'.
   * <P>
   * The id string for this method would be <CODE>
   * ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver#getMethodFromString#(Ljava/lang/String)Ljava/lang/reflect/Method"
   * </CODE>.
   * <P>
   * Note: The class must declare the method, if it only inherits it from a super
   *     class, this method will throw an {@link java.lang.NoSuchMethodError
   *     NoSuchMethodError}.
   *
   * @param id unique method identification string
   * @return Member the reflected object for <CODE>id</CODE> (type is either
   *   {@link java.lang.reflect.Method} or {@link java.lang.reflect.Constructor}).
   * @throws java.lang.ClassNotFoundException can not find the class, declaring the method.
   * @throws ch.ethz.jvmai.InvalidIdException id has wrong format (doesn't contain two '#').
   * @throws java.lang.NoSuchMethodError can not find the method in the declaring class.
   * @throws ch.ethz.jvmai.JVMAIRuntimeException class was not initialized.
   */
  // id strings are usually generated by HotSwapClassRegister and consumed by the
  // various Weavers.
  public static Member getMethodFromString( String id ) throws ClassNotFoundException {
    if( null == contingencyLoader )
      throw new JVMAIRuntimeException("not initialized");

    // 1 Try to get it from cache
    Object cachedResult = (Member) resolvedMethods.get( id );
    if( null != cachedResult )
      return (Member) cachedResult;

    // 2. find the positions of the separators
    int sep1 = id.indexOf( '#' );      // between class name & method name
    int sep2 = id.indexOf( '#', sep1 + 1 )// between method name & signature
    int sep3 = id.indexOf( '#', sep2 + 1 )// indicates a static method (if present)
    // Check if the seperators are valid
    if( sep1 < 0 || sep2 < 0)
      throw new InvalidIdException("Invalid method identifier string: " + id );
    // 3. get the (sub)strings
    Class clazz = Class.forName(id.substring(0,sep1).replace( '/', '.'), true, contingencyLoader  );  
    String methodName = id.substring( sep1 + 1, sep2 );
    // 4. get the method object
    Member result;
    if( -1 == sep3 ) {          // non static method
      String signature = id.substring( sep2 + 1 );
      result = getMethodFromStrings( clazz, methodName, signature, false );
    }
    else {                // static method
      String signature = id.substring( sep2 + 1, sep3 );
      result = getMethodFromStrings( clazz, methodName, signature, true );
    }
    // 5. cache it.
    resolvedMethods.put( id, result );
    return result;
  }

  /**
   * Returns the reflected Method, for a id string containing the class name,
   * the method name and it's signature, separated by '#'.
   * <P>
   * The id string for this method would be <CODE>
   * ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver#getMethodFromString#(Ljava/lang/String)Ljava/lang/reflect/Method"
   * </CODE>.
   * <P>
   * Note: The class must declare the method, if it only inherits it from a super
   *     class, this method will throw an {@link java.lang.NoSuchMethodError
   *     NoSuchMethodError}.
   *
   * @param className String holding the full qualified name of the class.
   * @param methodName String holding the methods name.
   * @param signature String holding the methods signature.
   * @param isStatic <CODE>true</CODE> if the method is static.
   * @return Member the reflected Method or Constructor object.
   * @throws java.lang.ClassNotFoundException can not find the class, declaring the method.
   * @throws ch.ethz.jvmai.InvalidIdException id has wrong format (doesn't contain two '#').
   * @throws java.lang.NoSuchMethodError can not find the method in the declaring class.
   * @throws ch.ethz.jvmai.JVMAIRuntimeException class was not initialized.
   */
  public static Member getMethodFromString( String className, String methodName, String signature, boolean isStatic ) throws ClassNotFoundException {
    if( null == contingencyLoader )
      throw new JVMAIRuntimeException("not initialized");
    // 1. Try to get it from cache
    String key = className + '#' + methodName + '#' + signature + (isStatic ? "#" : "");
    Object cachedResult = resolvedMethods.get( key );
    if( null != cachedResult )
      return (Member) cachedResult;
    // 2. Resolve the class
    Class clazz = Class.forName( className.replace( '/', '.'), true, contingencyLoader  );  
    // 3. Get the method object
    Member result = getMethodFromStrings( clazz, methodName, signature, isStatic );
    // 4. Cache it.
    resolvedMethods.put( key, result );
    return result;
  }

  /**
   * Returns the reflected Field, for a id string containing the class name,
   * the field name and it's signature separated by '#'.
   * <P>
   * Note: The class must declare the field, if it only inherits it from a super
   *     class, this method will throw an {@link java.lang.NoSuchFieldException
   *     NoSuchFieldException}.
   *
   * @param id String holding an unique identiefier for the field.
   * @param isStatic <CODE>true</CODE> if the field is static.
   * @return Field
   * @throws ClassNotFoundException can not find the class, the field belongs to.
   * @throws NoSuchFieldException can not find the field
   * @throws InvalidIdException the id string is not well formated.
   */
  public static Field getFieldFromString( String id, boolean isStatic ) throws ClassNotFoundException, NoSuchFieldException {
    if( null == contingencyLoader )
      throw new JVMAIRuntimeException("not initialized");
    // 1. try to get it from cache
    Object cachedResult = resolvedFields.get( id );
    if( null != cachedResult )
      return (Field) cachedResult;

    // 2. Find the position of the separator
    // In most cases the full class name is longer as the simple
    // field name, so it's faster to search from the end to the beginning.
    int sep1 = id.indexOf('#');
    int sep2 = id.lastIndexOf('#');
    if( sep1 >= sep2 || sep1 < 0 )
      throw new InvalidIdException("Invalid field identifier string: " + id );

    // 3. Get the substrings
    String className = id.substring( 0, sep1 );
    String fieldName = id.substring( sep1 + 1, sep2 );
    String signature = id.substring( sep2 + 1 );
    // 4. Resolve the class
    Class clazz = Class.forName( className.replace( '/', '.'), true, contingencyLoader );
    // 5. Get the field object
    Field result = getFieldFromStrings( clazz, fieldName, signature, isStatic );
    // 6. Cache the result
    resolvedFields.put( id, result );
    return result;
  }

  /**
   * Returns the reflected Field, for a id string containing the class name,
   * the field name and it's signature separated by '#'.
   * <P>
   * Note: The class must declare the field, if it only inherits it from a super
   *     class, this method will throw an {@link java.lang.NoSuchFieldException
   *     NoSuchFieldException}.
   *
   * @param className String holding the full qualified class name.
   * @param fieldName String holding the fields name.
   * @param signature String holding the signature (type) of the field.
   * @param isStatic <CODE>true</CODE> if the field is static.
   * @return Field
   * @throws ClassNotFoundException can not find the class, the field belongs to.
   * @throws NoSuchFieldException can not find the field
   * @throws InvalidIdException the id string is not well formated.
   */
  public static Field getFieldFromString( String className, String fieldName, String signature, boolean isStatic ) throws ClassNotFoundException, NoSuchFieldException {
    if( null == contingencyLoader )
      throw new JVMAIRuntimeException("not initialized");
    // 1. Try to get it from cache
    String key = className + "#" + fieldName + "#" + signature;
    Object cachedResult = resolvedFields.get( key );
    if( null != cachedResult )
      return (Field) cachedResult;
    // 2. Resolve the class
    Class clazz = Class.forName( className.replace( '/', '.'), true, contingencyLoader );
    // 3. Get the field object
    Field result = getFieldFromStrings( clazz, fieldName, signature, isStatic );
    // 4. Cache the field
    resolvedFields.put( key, result );
    return result;
  }

  /**
   * Returns a BCEL class of a java class.
   *
   * @param cls - the Java class
   * @return JavaClass BCEL class for <CODE>cls</CODE>
   * @throws JVMAIRuntimeException the class is not initialized, <CODE>startup()</CODE>
   *             was never invoked.
   * @throws ClassNotFoundException can not find the class or the class file
   */
  //  public static JavaClass getBCELClassDefinition( Class cls ) throws ClassNotFoundException {   //BEFORE - BUGFIX - multiple class loaders
  //    if( null == classRepository )
  //      throw new JVMAIRuntimeException("not initialized");
  //   
  //    return classRepository.loadClass( cls );  // throws an exception, if not found
  //  }

  /**
   * Checks if a class is known to BCEL
   * @param cls - the Java class
   * @return true if the class has been found in the repository
   */
  private static boolean isClassKnownToBCEL(Class cls) {              //PLUS - BUGFIX - multiple class loaders
    return classRepository.findClass(cls.getName()) != null;   
  }     

  /**
   * Inserts a class into the BCEL repository
   * @param cls Class to be inserted
   * @throws ClassFormatException
   * @throws IOException
   */
  private static void insertClassIntoBCEL(Class cls) throws Exception {    //PLUS - BUGFIX - multiple class loaders
    String className = cls.getName();

    if (cls.getClassLoader() != null) {
      String resourceName = className.replace( '.', '/') + ".class";
      InputStream classInputStream = cls.getClassLoader().getResourceAsStream(resourceName);

      if (classInputStream != null) {
        ClassParser cp = new ClassParser(classInputStream, resourceName);
        classRepository.storeClass( cp.parse() );
      } else {
        System.err.println("Resource " + resourceName + " not found.");
      }
    }
  }

  /**
   * Returns a BCEL class of a Java class.
   *
   * @param cls - the Java class
   * @return JavaClass BCEL class for <CODE>cls</CODE>
   * @throws JVMAIRuntimeException the class is not initialized, <CODE>startup()</CODE>
   *             was never invoked.
   * @throws ClassNotFoundException can not find the class or the class file
   */
  public static JavaClass getBCELClassDefinition( Class cls ) throws ClassNotFoundException {    //PLUS - BUGFIX - multiple class loaders

    if( null == classRepository )
      throw new JVMAIRuntimeException("not initialized");

    try {
      if (!isClassKnownToBCEL(cls)) insertClassIntoBCEL(cls);
    } catch (Exception e) {
      System.err.println("Was not able to add class " + cls.getName() + " of classloader " + cls.getClassLoader() + " to BCEL.");
      throw new ClassNotFoundException(e.getClass().toString());
    }

    return classRepository.loadClass( cls )// throws an exception, if not found
  }

  /**
   * Returns the original class implementation from a class file
   * in CLASS_PATH, if available. This is deprecated use
   * {@link #getBCELClassDefinition(Class)} instead.
   *
   * @param cls Class thats implementation should be returned.
   * @return InputStream with the contents of the class file.
   * @exception RuntimeException if class file was not found.
   * @exception NullPointerException if <CODE>cls</CODE> is <CODE>null</CODE>.
   *
   * @deprecated
   */
  public java.io.InputStream getOriginalClassDefinition( Class cls ) throws IOException {
    if( null == cls )
      throw new NullPointerException();

    java.io.InputStream result;

    // Try to get the definition from the cache
    Object classCache = classFileMap.get( cls );
    if( null == classCache ) {
      // Get definition from class file
      ClassLoader cl= cls.getClassLoader();
      if (cl == null)
        cl = contingencyLoader;

      String fileName = cls.getName().replace( '.', '/' ) + ".class";
      result = cl.getResourceAsStream( fileName );

      if( null == result )
        throw new
        JVMAIRuntimeException( "JVMAspectInterface.getOriginalClassDefinition: could not find classfile " + cls.getName() );

      // Add definition to cache
      int fileSize = result.available();
      byte[] classDef = new byte[ fileSize ];

      if( result.markSupported() ) {
        result.mark( fileSize );
        result.read( classDef );
        result.reset();
      }
      else {
        result.read( classDef );
        result = new ByteArrayInputStream( classDef );
      }

      classFileMap.put( cls, classDef );
    }
    else
      // Definition was in cache, just have to wrap it in a stream.
      result = new ByteArrayInputStream((byte[]) classCache);

    return result;
  }

  //------------------------------------------------------------------------------
  // Native methods
  //------------------------------------------------------------------------------

  /**
   * Returns a reflected method object for a method identified by
   * it's name and signature.
   * <P>
   * This is a native function because some (synthetic) methods may not be
   * accessed via the Java reflection API (and this should also be faster).
   *
   * @param className name of a class holding the method (all classes containing
   * this method are valid, not only the declaring class)
   * @param methodName name of the method
   * @param signature method's signature.
   * @param isStatic <CODE>true</CODE> if the method is a static class member.
   * @return Member reflected object representing the method, may either be
   * of type {@link java.lang.reflected.Method java.lang.reflected.Method}
   * or {@link java.lang.reflected.Constructor java.lang.reflected.Constructor}.
   */
  private static native Member getMethodFromStrings( Class clazz, String methodName, String signature, boolean isStatic );
  /**
   * Returns a reflected field object for a field identified by
   * it's name and signature.
   * <P>
   * This is a native function because some fields may not be
   * accessed via the Java reflection API (and this should also be faster).
   *
   * @param className name of a class holding the field (all classes containing
   * this method are valid, not only the declaring class)
   * @param fieldName name of the field
   * @param signature the signature of the field (type).
   * @param isStatic <CODE>true</CODE> if the field is a static class member.
   * @return Field reflected object representing the field.
   */
  private static native Field getFieldFromStrings( Class clazz, String fieldName, String signature, boolean isStatic );
  /// initializes the native part of this class.
  private native void doStartUp( String[] prefixes, boolean openWorld );
}
TOP

Related Classes of ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl

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.