//
// 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 );
}