0001: ///
0002: // This file is part of the prose package.
0003: //
0004: // The contents of this file are subject to the Mozilla Public License
0005: // Version 1.1 (the "License"); you may not use this file except in
0006: // compliance with the License. You may obtain a copy of the License at
0007: // http://www.mozilla.org/MPL/
0008: //
0009: // Software distributed under the License is distributed on an "AS IS" basis,
0010: // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0011: // for the specific language governing rights and limitations under the
0012: // License.
0013: //
0014: // The Original Code is prose.
0015: //
0016: // Contributor(s):
0017: // $Id$
0018: // =====================================================================
0019: //
0020: // (history at end)
0021: //
0022:
0023: package ch.ethz.inf.iks.jvmai.jvmdi;
0024:
0025: import java.util.Set;
0026: import java.util.HashSet;
0027: import java.util.Iterator;
0028: import java.lang.reflect.*;
0029: import java.io.IOException;
0030: import java.io.ByteArrayInputStream;
0031: import java.io.InputStream;
0032:
0033: import org.apache.bcel.classfile.ClassParser;
0034: import org.apache.bcel.classfile.JavaClass;
0035: import org.apache.bcel.generic.ClassGen;
0036:
0037: import ch.ethz.jvmai.*;
0038:
0039: /**
0040: * HotSwapAspectInterfaceImpl class.
0041: *
0042: * @author Angela Nicoara
0043: * @author Gerald Linhofer
0044: * @version $Revision: 1.1.2.5 $
0045: */
0046: public class HotSwapAspectInterfaceImpl extends AspectInterfaceImpl {
0047:
0048: /**
0049: * Gathers and holds informations about field and method call join points
0050: */
0051: protected static HotSwapClassRegister classRegister = null;
0052: /**
0053: * Caches class definitions, which where fetched by {@link #getOriginalClassDefinition}
0054: * @deprecated
0055: */
0056: protected static CacheMap classFileMap = null;
0057:
0058: /**
0059: * Caches reflected Method objects resolved by
0060: * the <CODE>getMethodFromString()</CODE> methods.
0061: */
0062: protected static CacheMap resolvedMethods = null;
0063: /**
0064: * Caches reflected Field objects resolved by
0065: * the <CODE>getFieldFromString()</CODE> methods.
0066: */
0067: protected static CacheMap resolvedFields = null;
0068: //
0069: // Arrays holding the tags for active advices, tags will be
0070: // added by the set..Watch(), removed by
0071: // clear...Watch() and used in doOn...() methods.
0072: //
0073: protected static Object methodEntryTags[] = null;
0074: protected static Object methodExitTags[] = null;
0075: protected static Object constructorTags[] = null;
0076: // protected static Object methodCallTags[] = null;
0077: // protected static Object methodReturnTags[] = null;
0078: protected static Object fieldAccessTags[] = null;
0079: protected static Object fieldModificationTags[] = null;
0080:
0081: /**
0082: * <CODE>true</CODE> if HotSwapAspectInterfaceImpl was initialized.
0083: */
0084: protected static boolean initialized = false;
0085:
0086: /**
0087: * Replacement tag, will be used as tag, if the user supplied tag
0088: * is <CODE>null</CODE>. (Required to store the tag in data
0089: * structures that didn't allow <CODE>null</CODE> entries.)
0090: */
0091: protected static Object aopNullTag = new Object();
0092:
0093: //
0094: // Join point objects for the various join points, the objects are preallocated
0095: // and will be reused at each advice call from the same join point type.
0096: // (Dont forget to SYNCHRONIZE uses of these objects!!!)
0097: //
0098: protected static HotSwapMethodEntryJoinPointImpl methodEntryJoinPoint = new HotSwapMethodEntryJoinPointImpl();
0099: protected static HotSwapMethodExitJoinPointImpl methodExitJoinPoint = new HotSwapMethodExitJoinPointImpl();
0100: protected static HotSwapConstructorJoinPointImpl constructorJoinPoint = new HotSwapConstructorJoinPointImpl();
0101: protected static HotSwapFieldAccessJoinPointImpl fieldAccessJoinPoint = new HotSwapFieldAccessJoinPointImpl();
0102: protected static HotSwapFieldModificationJoinPointImpl fieldModificationJoinPoint = new HotSwapFieldModificationJoinPointImpl();
0103:
0104: //
0105: // Holds threads that will be ignored, if they call a doOn...() callback method.
0106: // Used during advice weaving to supress notifications.
0107: //
0108: protected static Set suspendedThreads = new HashSet(1024);
0109: // protected static Set<Thread> suspendedThreads = new HashSet<Thread>(1024); // only JDK 1.5 or above
0110:
0111: // Class loader used by 'get*ClassDefinition' and 'getMethodFromString'.
0112: private static ClassLoader contingencyLoader = null;
0113:
0114: // holds the instance of HotSwapAspectInteface (Singelton Pattern)
0115: private static HotSwapAspectInterfaceImpl instance;
0116:
0117: /**
0118: * Constructor. Dont call it, use {@link HotSwapAspectInterfaceImpl#getInstance
0119: * getInstance()} to create an instance of this class.
0120: * <P>
0121: * This is not private to allow unit testing.
0122: */
0123: protected HotSwapAspectInterfaceImpl() {
0124: }
0125:
0126: /**
0127: * Returns the instance of HotSwapAspectInterfaceImpl and creates it
0128: * if required. There's only one instance of this class (Singelton Pattern).
0129: *
0130: * @return HotSwapAspectInterfaceImpl instance
0131: */
0132: public static HotSwapAspectInterfaceImpl getInstance() {
0133: if (null == instance)
0134: instance = new HotSwapAspectInterfaceImpl();
0135: return instance;
0136: }
0137:
0138: //------------------------------------------------------------------------------------------------------------------
0139: // Interface for the JoinPointManager
0140: //------------------------------------------------------------------------------------------------------------------
0141:
0142: /**
0143: * Initializes the underlying jvmai system.
0144: * <p>
0145: * In addition, this method takes a list of java package-names and a
0146: * boolean indicating how to interpret this prefixes. The prefixes are
0147: * used by the jvmai system to determine the set of classes beeing
0148: * relevant to the system at all.
0149: * Depeding on the value of <code>openWorldAssumption</code>, prefixes
0150: * are interpreted as followed:
0151: * <p>
0152: * <code>openWorldAssumption == true</code><br>
0153: * The jvmai-system is instructed to treat ALL classes as relevant,
0154: * EXCEPT the ones contained in a packages starting with one of the
0155: * supplied prefixes in <code>packagePrefixes</code>
0156: * <p>
0157: * <code>openWorldAssumption == false</code><br>
0158: * The jvmai-system is instructed to treat as relevant ONLY the classes
0159: * contained in a packages starting with one of the supplied prefixes
0160: * in <code>packagePrefixes</code>
0161: *
0162: * @param packagePrefixes List of prefixes for java package-names.
0163: * @param openWorldAssumption Specifies how the prefixes are interpreted.
0164: * @exception StartupException Use <code>StartupException.getMessage()</code> to get a detailed description
0165: */
0166: public synchronized void startup(String[] packagePrefixes,
0167: boolean openWorldAssumption) {
0168: if (null == packagePrefixes)
0169: packagePrefixes = new String[0];
0170:
0171: // make sure all classes that are addressed during event notification are loaded already here
0172: Class toload;
0173: toload = ch.ethz.inf.iks.jvmai.jvmdi.JumpFinallyVisitor.class;
0174: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapProvider.class;
0175: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapJoinPointImpl.class;
0176: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapMethodEntryJoinPointImpl.class;
0177: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapMethodExitJoinPointImpl.class;
0178: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldJoinPointImpl.class;
0179: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldAccessJoinPointImpl.class;
0180: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldModificationJoinPointImpl.class;
0181: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapSignatureImpl.class;
0182: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassRegister.class;
0183: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver.class;
0184: toload = ch.ethz.inf.iks.jvmai.jvmdi.HotSwapFieldWeaver.class;
0185: toload = ch.ethz.inf.iks.jvmai.jvmdi.CacheMap.class;
0186: toload = ch.ethz.jvmai.MethodRedefineJoinPoint.class;
0187: toload = ch.ethz.jvmai.UnmodifiableClassException.class;
0188: toload = ch.ethz.jvmai.IlligalClassFormatException.class;
0189: // BCEL classes must be loaded at startup to prevent
0190: // dead locks, if BCEL is used to parse classes on class
0191: // load.
0192: toload = org.apache.bcel.Constants.class;
0193: toload = org.apache.bcel.classfile.AccessFlags.class;
0194: toload = org.apache.bcel.classfile.Attribute.class;
0195: toload = org.apache.bcel.classfile.ClassParser.class;
0196: toload = org.apache.bcel.classfile.JavaClass.class;
0197: toload = org.apache.bcel.classfile.FieldOrMethod.class;
0198: toload = org.apache.bcel.classfile.Method.class;
0199: toload = org.apache.bcel.classfile.Field.class;
0200: toload = org.apache.bcel.classfile.Code.class;
0201: toload = org.apache.bcel.classfile.Constant.class;
0202: toload = org.apache.bcel.classfile.ConstantCP.class;
0203: toload = org.apache.bcel.classfile.ConstantDouble.class;
0204: toload = org.apache.bcel.classfile.ConstantFieldref.class;
0205: toload = org.apache.bcel.classfile.ConstantFloat.class;
0206: toload = org.apache.bcel.classfile.ConstantInteger.class;
0207: toload = org.apache.bcel.classfile.ConstantInterfaceMethodref.class;
0208: toload = org.apache.bcel.classfile.ConstantMethodref.class;
0209: toload = org.apache.bcel.classfile.ConstantNameAndType.class;
0210: toload = org.apache.bcel.classfile.ConstantString.class;
0211: toload = org.apache.bcel.classfile.ConstantUtf8.class;
0212: toload = org.apache.bcel.classfile.ConstantClass.class;
0213: toload = org.apache.bcel.classfile.ConstantValue.class;
0214: toload = org.apache.bcel.classfile.ConstantPool.class;
0215: toload = org.apache.bcel.classfile.InnerClass.class;
0216: toload = org.apache.bcel.classfile.InnerClasses.class;
0217: toload = org.apache.bcel.classfile.ExceptionTable.class;
0218: toload = org.apache.bcel.classfile.LineNumber.class;
0219: toload = org.apache.bcel.classfile.LineNumberTable.class;
0220: toload = org.apache.bcel.classfile.LocalVariable.class;
0221: toload = org.apache.bcel.classfile.LocalVariableTable.class;
0222: toload = org.apache.bcel.classfile.StackMapEntry.class;
0223: toload = org.apache.bcel.classfile.StackMapType.class;
0224: toload = org.apache.bcel.classfile.StackMap.class;
0225: toload = org.apache.bcel.classfile.Signature.class;
0226: toload = org.apache.bcel.classfile.SourceFile.class;
0227: toload = org.apache.bcel.classfile.Synthetic.class;
0228: toload = org.apache.bcel.classfile.Deprecated.class;
0229: toload = org.apache.bcel.classfile.Utility.class;
0230: toload = org.apache.bcel.generic.AALOAD.class;
0231: toload = org.apache.bcel.generic.AASTORE.class;
0232: toload = org.apache.bcel.generic.ACONST_NULL.class;
0233: toload = org.apache.bcel.generic.ALOAD.class;
0234: toload = org.apache.bcel.generic.ANEWARRAY.class;
0235: toload = org.apache.bcel.generic.ARETURN.class;
0236: toload = org.apache.bcel.generic.ArithmeticInstruction.class;
0237: toload = org.apache.bcel.generic.ArrayInstruction.class;
0238: toload = org.apache.bcel.generic.ARRAYLENGTH.class;
0239: toload = org.apache.bcel.generic.ArrayType.class;
0240: toload = org.apache.bcel.generic.ALOAD.class;
0241: toload = org.apache.bcel.generic.ASTORE.class;
0242: toload = org.apache.bcel.generic.BALOAD.class;
0243: toload = org.apache.bcel.generic.BasicType.class;
0244: toload = org.apache.bcel.generic.BASTORE.class;
0245: toload = org.apache.bcel.generic.BIPUSH.class;
0246: toload = org.apache.bcel.generic.BranchHandle.class;
0247: toload = org.apache.bcel.generic.BranchInstruction.class;
0248: toload = org.apache.bcel.generic.BREAKPOINT.class;
0249: toload = org.apache.bcel.generic.CALOAD.class;
0250: toload = org.apache.bcel.generic.CASTORE.class;
0251: toload = org.apache.bcel.generic.CHECKCAST.class;
0252: toload = org.apache.bcel.generic.ClassGen.class;
0253: toload = org.apache.bcel.generic.CodeExceptionGen.class;
0254: toload = org.apache.bcel.generic.ConstantPoolGen.class;
0255: toload = org.apache.bcel.generic.ConversionInstruction.class;
0256: toload = org.apache.bcel.generic.CPInstruction.class;
0257: toload = org.apache.bcel.generic.D2F.class;
0258: toload = org.apache.bcel.generic.D2I.class;
0259: toload = org.apache.bcel.generic.D2L.class;
0260: toload = org.apache.bcel.generic.DADD.class;
0261: toload = org.apache.bcel.generic.DALOAD.class;
0262: toload = org.apache.bcel.generic.DASTORE.class;
0263: toload = org.apache.bcel.generic.DCMPG.class;
0264: toload = org.apache.bcel.generic.DCMPL.class;
0265: toload = org.apache.bcel.generic.DCONST.class;
0266: toload = org.apache.bcel.generic.DDIV.class;
0267: toload = org.apache.bcel.generic.DLOAD.class;
0268: toload = org.apache.bcel.generic.DMUL.class;
0269: toload = org.apache.bcel.generic.DNEG.class;
0270: toload = org.apache.bcel.generic.DREM.class;
0271: toload = org.apache.bcel.generic.DRETURN.class;
0272: toload = org.apache.bcel.generic.DSTORE.class;
0273: toload = org.apache.bcel.generic.DSUB.class;
0274: toload = org.apache.bcel.generic.DUP.class;
0275: toload = org.apache.bcel.generic.DUP_X1.class;
0276: toload = org.apache.bcel.generic.DUP_X2.class;
0277: toload = org.apache.bcel.generic.DUP2.class;
0278: toload = org.apache.bcel.generic.DUP2_X1.class;
0279: toload = org.apache.bcel.generic.DUP2_X2.class;
0280: toload = org.apache.bcel.generic.F2D.class;
0281: toload = org.apache.bcel.generic.F2I.class;
0282: toload = org.apache.bcel.generic.F2L.class;
0283: toload = org.apache.bcel.generic.FADD.class;
0284: toload = org.apache.bcel.generic.FALOAD.class;
0285: toload = org.apache.bcel.generic.FASTORE.class;
0286: toload = org.apache.bcel.generic.FCMPG.class;
0287: toload = org.apache.bcel.generic.FCMPL.class;
0288: toload = org.apache.bcel.generic.FCONST.class;
0289: toload = org.apache.bcel.generic.FDIV.class;
0290: toload = org.apache.bcel.generic.FieldGen.class;
0291: toload = org.apache.bcel.generic.FieldGenOrMethodGen.class;
0292: toload = org.apache.bcel.generic.FieldInstruction.class;
0293: toload = org.apache.bcel.generic.FieldOrMethod.class;
0294: toload = org.apache.bcel.generic.FLOAD.class;
0295: toload = org.apache.bcel.generic.FMUL.class;
0296: toload = org.apache.bcel.generic.FNEG.class;
0297: toload = org.apache.bcel.generic.FREM.class;
0298: toload = org.apache.bcel.generic.FRETURN.class;
0299: toload = org.apache.bcel.generic.FSTORE.class;
0300: toload = org.apache.bcel.generic.FSUB.class;
0301: toload = org.apache.bcel.generic.GETFIELD.class;
0302: toload = org.apache.bcel.generic.GETSTATIC.class;
0303: toload = org.apache.bcel.generic.GOTO.class;
0304: toload = org.apache.bcel.generic.GOTO_W.class;
0305: toload = org.apache.bcel.generic.GotoInstruction.class;
0306: toload = org.apache.bcel.generic.I2B.class;
0307: toload = org.apache.bcel.generic.I2C.class;
0308: toload = org.apache.bcel.generic.I2D.class;
0309: toload = org.apache.bcel.generic.I2F.class;
0310: toload = org.apache.bcel.generic.I2L.class;
0311: toload = org.apache.bcel.generic.I2S.class;
0312: toload = org.apache.bcel.generic.IADD.class;
0313: toload = org.apache.bcel.generic.IALOAD.class;
0314: toload = org.apache.bcel.generic.IAND.class;
0315: toload = org.apache.bcel.generic.IASTORE.class;
0316:
0317: super .startup(packagePrefixes, openWorldAssumption);
0318:
0319: if (initialized)
0320: return;
0321:
0322: // initialize static fields
0323: methodEntryTags = new Object[1024];
0324: methodExitTags = new Object[1024];
0325: constructorTags = new Object[1024];
0326: fieldAccessTags = new Object[1024];
0327: fieldModificationTags = new Object[1024];
0328: // methodCallTags = new Object[1024];
0329: // methodReturnTags = new Object[1024];
0330:
0331: doStartUp(packagePrefixes, openWorldAssumption);
0332:
0333: if (contingencyLoader == null) {
0334: Iterator i = getLoadedClasses().iterator();
0335: while (i.hasNext() && contingencyLoader == null) {
0336: Class cls = (Class) i.next();
0337: contingencyLoader = cls.getClassLoader();
0338: }
0339: classFileMap = new CacheMap(1024);
0340: resolvedMethods = new CacheMap(1024);
0341: resolvedFields = new CacheMap(1024);
0342: classRegister = HotSwapClassRegister.getInstance();
0343: }
0344:
0345: initialized = true;
0346:
0347: HotSwapClassWeaver.setAspectInterface(this );
0348: HotSwapClassRegister.setAspectInterface(this , packagePrefixes,
0349: openWorldAssumption);
0350: }
0351:
0352: /**
0353: * Teardown the AOP support. As a result,
0354: * no events will be sent to the JoinPointHook.
0355: */
0356: public synchronized void teardown() {
0357: super .teardown();
0358:
0359: // static members
0360: initialized = false;
0361: hook = null;
0362: methodEntryTags = null;
0363: methodExitTags = null;
0364: constructorTags = null;
0365: fieldAccessTags = null;
0366: fieldModificationTags = null;
0367: // methodCallTags = null;
0368: // methodReturnTags = null;
0369:
0370: suspendedThreads.clear();
0371: classFileMap.clear();
0372: resolvedMethods.clear();
0373: resolvedFields.clear();
0374:
0375: classRegister.reset();
0376: }
0377:
0378: /**
0379: * Sets a watch on a method entry joinpoint.
0380: *
0381: * @param m the method to be watched.
0382: * @param aopTag A user-defined object saved with this watch.
0383: * When the joinpoint is reached, this object is
0384: * passed to the JoinPointHook as part of the
0385: * JoinPoint-instance. This object may be <code>null</code>.
0386: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0387: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0388: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0389: * @exception CannotSetWatchException The method must not be abstract or native.
0390: * @exception WatchAlreadySetException There already exists a entry-watch on the method.
0391: */
0392: public void setMethodEntryWatch(Method m, Object aopTag) {
0393: // check preconditions
0394: checkWatchPrecondition(m, aopTag);
0395:
0396: if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
0397: throw new CannotSetWatchException(
0398: "HotSwapAspectInterfaceImpl.setMethodEntryWatch: cannot set watches on interfaces");
0399:
0400: synchronized (methodEntryTags) {
0401: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0402: methodEntryTags = setWatch(methodEntryTags, aopTag, mw
0403: .getTargetId());
0404: mw.setMethodEntryEnabled(true);
0405: }
0406: }
0407:
0408: /**
0409: * Clears a watch on a method entry joinpoint.
0410: *
0411: * @param m the method beeing watched.
0412: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0413: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0414: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0415: * @exception WatchNotSetException There exists no entry-watch on the method.
0416: */
0417: public synchronized void clearMethodEntryWatch(Method m) {
0418: // preconditions
0419: if (!initialized)
0420: throw new NotInitializedException();
0421: if (m == null)
0422: throw new NullPointerException(
0423: "Parameter `m' must not be null.");
0424: if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
0425: throw new CannotSetWatchException(
0426: "HotSwapAspectInterfaceImpl.clearMethodEntryWatch: cannot clear watches on interfaces");
0427:
0428: //System.out.println("HotSwapAspectInterfaceImpl.clearMethodEntryWatch(): " + m);
0429: synchronized (methodEntryTags) {
0430: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0431: clearWatch(methodEntryTags, mw.getTargetId());
0432: mw.setMethodEntryEnabled(false);
0433: }
0434: }
0435:
0436: /**
0437: * Sets a watch on a method exit joinpoint.
0438: *
0439: * @param m the method to be watched.
0440: * @param aopTag A user-defined object saved with this watch.
0441: * When the joinpoint is reached, this object is
0442: * passed to the JoinPointHook as part of the
0443: * JoinPoint-instance. This object may be <code>null</code>.
0444: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0445: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0446: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0447: * @exception CannotSetWatchException The method must not be abstract or native.
0448: * @exception WatchAlreadySetException There already exists a exit-watch on the method.
0449: */
0450: public synchronized void setMethodExitWatch(Method m, Object aopTag) {
0451: // preconditions
0452: checkWatchPrecondition(m, aopTag);
0453: if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
0454: throw new CannotSetWatchException("Method is abstract: "
0455: + m);
0456:
0457: //System.out.println("HotSwapAspectInterfaceImpl.setMethodExitWatch(): " + m);
0458: synchronized (methodExitTags) {
0459: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0460: methodExitTags = setWatch(methodExitTags, aopTag, mw
0461: .getTargetId());
0462: mw.setMethodExitEnabled(true);
0463: }
0464: }
0465:
0466: /**
0467: * Clears a watch on a method exit joinpoint.
0468: *
0469: * @param m the method beeing watched.
0470: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0471: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0472: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0473: * @exception WatchNotSetException There exists no exit-watch on the method.
0474: */
0475: public void clearMethodExitWatch(Method m) {
0476: // preconditions
0477: if (!initialized)
0478: throw new NotInitializedException();
0479: if (m == null)
0480: throw new NullPointerException(
0481: "Parameter `m' must not be null.");
0482: if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
0483: throw new CannotSetWatchException("Method is abstract: "
0484: + m);
0485:
0486: //System.out.println("HotSwapAspectInterfaceImpl.clearMethodEntryWatch(): " + m);
0487: synchronized (methodExitTags) {
0488: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0489: clearWatch(methodExitTags, mw.getTargetId());
0490: mw.setMethodExitEnabled(false);
0491: }
0492: }
0493:
0494: /**
0495: * Sets a watch on a constructor joinpoint.
0496: *
0497: * @param m the constructor to be watched.
0498: * @param aopTag A user-defined object saved with this watch.
0499: * When the joinpoint is reached, this object is
0500: * passed to the JoinPointHook as part of the
0501: * JoinPoint-instance. This object may be <code>null</code>.
0502: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0503: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0504: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0505: * @exception CannotSetWatchException The method must not be abstract or native.
0506: * @exception WatchAlreadySetException There already exists a entry-watch on the method.
0507: */
0508: public void setConstructorWatch(Constructor m, Object aopTag) {
0509: // check preconditions
0510: checkWatchPrecondition(m, aopTag);
0511:
0512: if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
0513: throw new CannotSetWatchException(
0514: "HotSwapAspectInterfaceImpl.setConstructorWatch: cannot set watches on interfaces");
0515:
0516: synchronized (constructorTags) {
0517: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0518: constructorTags = setWatch(constructorTags, aopTag, mw
0519: .getTargetId());
0520: // TODO: change to something like constructor enabled
0521: mw.setMethodEntryEnabled(true);
0522: }
0523: }
0524:
0525: /**
0526: * Clears a watch on a constructor joinpoint.
0527: *
0528: * @param m the constructor beeing watched.
0529: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0530: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0531: * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
0532: * @exception WatchNotSetException There exists no entry-watch on the method.
0533: */
0534: public synchronized void clearConstructorWatch(Constructor m) {
0535: // preconditions
0536: if (!initialized)
0537: throw new NotInitializedException();
0538: if (m == null)
0539: throw new NullPointerException(
0540: "Parameter `m' must not be null.");
0541: if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
0542: throw new CannotSetWatchException(
0543: "HotSwapAspectInterfaceImpl.clearConstructorWatch: cannot clear watches on interfaces");
0544:
0545: //System.out.println("HotSwapAspectInterfaceImpl.clearConstructorWatch(): " + m);
0546: synchronized (constructorTags) {
0547: MethodWeaver mw = HotSwapClassWeaver.getWeaver(m);
0548: clearWatch(constructorTags, mw.getTargetId());
0549: // TODO: change to something like constructor enabled
0550: mw.setMethodEntryEnabled(false);
0551: }
0552: }
0553:
0554: /**
0555: * Sets a watch on a field access joinpoint.
0556: *
0557: * @param field the field to be watched.
0558: * @param aopTag A user-defined object saved with this watch.
0559: * When the joinpoint is reached, this object is
0560: * passed to the JoinPointHook as part of the
0561: * JoinPoint-instance. This object may be <code>null</code>.
0562: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0563: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0564: * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
0565: * @exception CannotSetWatchException ?
0566: * @exception WatchAlreadySetException There already exists a access-watch on the field.
0567: */
0568: public void setFieldAccessWatch(Field field, Object aopTag) {
0569: // check preconditions
0570: checkWatchPrecondition(field, aopTag);
0571:
0572: synchronized (fieldAccessTags) {
0573: HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver(field);
0574: fieldAccessTags = setWatch(fieldAccessTags, aopTag, fw
0575: .getTargetId());
0576: fw.setFieldAccessEnabled(true);
0577: }
0578: }
0579:
0580: /**
0581: * Clears a watch on a field access joinpoint.
0582: *
0583: * @param field the field beeing watched.
0584: * @exception NotInitializedException Aspect-interface has not been intialized yet. Call <code>setup</code> first.
0585: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0586: * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
0587: * @exception WatchNotSetException There exists no access-watch on the field.
0588: */
0589: public void clearFieldAccessWatch(Field field) {
0590: if (!isInitialized || !initialized)
0591: throw new NotInitializedException(
0592: "HotSwapAspectInterfaceImpl.clearFieldAccessWatch: jvmai not initialized");
0593: if (field == null)
0594: throw new NullPointerException(
0595: "HotSwapAspectInterfaceImpl.clearFieldAccessWatch: null cls parameter");
0596:
0597: synchronized (fieldAccessTags) {
0598: HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver(field);
0599: clearWatch(fieldAccessTags, fw.getTargetId());
0600: fw.setFieldAccessEnabled(false);
0601: }
0602: }
0603:
0604: /**
0605: * Sets a watch on a field modification joinpoint.
0606: *
0607: * @param field the field to be watched.
0608: * @param aopTag A user-defined object saved with this watch.
0609: * When the joinpoint is reached, this object is
0610: * passed to the JoinPointHook as part of the
0611: * JoinPoint-instance. This object may be <code>null</code>.
0612: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0613: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0614: * @exception InvalidIdException There exist no field with id <code>fieldId</code> in class <code>cls</code>.
0615: * @exception CannotSetWatchException ?
0616: * @exception WatchAlreadySetException There already exists a modification-watch on the field.
0617: */
0618: public void setFieldModificationWatch(Field field, Object aopTag) {
0619: //System.out.println("HotSwapAspectInterfaceImpl.setFieldModificationWatch() for " + field );
0620: // check preconditions
0621: checkWatchPrecondition(field, aopTag);
0622:
0623: synchronized (fieldModificationTags) {
0624: HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver(field);
0625: fieldModificationTags = setWatch(fieldModificationTags,
0626: aopTag, fw.getTargetId());
0627: fw.setFieldModificationEnabled(true);
0628: }
0629: }
0630:
0631: /**
0632: * Clears a watch on a field modification joinpoint.
0633: *
0634: * @param field the field beeing watched.
0635: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0636: * @exception NullPointerException <code>cls</code> is <code>null</code>.
0637: * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
0638: * @exception WatchNotSetException There exists no modification-watch on the field.
0639: */
0640: public void clearFieldModificationWatch(Field field) {
0641: if (!isInitialized || !initialized)
0642: throw new NotInitializedException(
0643: "HotSwapAspectInterfaceImpl.clearFieldAccessWatch: jvmai not initialized");
0644: if (field == null)
0645: throw new NullPointerException(
0646: "HotSwapAspectInterfaceImpl.clearFieldAccessWatch: null cls parameter");
0647:
0648: synchronized (fieldModificationTags) {
0649: HotSwapFieldWeaver fw = HotSwapFieldWeaver.getWeaver(field);
0650: clearWatch(fieldModificationTags, fw.getTargetId());
0651: fw.setFieldModificationEnabled(false);
0652: }
0653: }
0654:
0655: /**
0656: * Suspend notification regarding the specified thread.
0657: * Successive calls to <code>suspendNotification</code>
0658: * have to be balanced by (at least) the same number of calls to
0659: * <code>resumeNotification</code>, or the jvmai-system
0660: * will not resume notification.
0661: *
0662: * @param thread Thread for which to disable notification.
0663: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0664: * @exception NullPointerException <code>thread</code> is <code>null</code>.
0665: */
0666: public void suspendNotification(Thread thread) {
0667: if (!initialized)
0668: throw new NotInitializedException();
0669: if (thread == null)
0670: throw new NullPointerException(
0671: "Parameter `thread' must not be null");
0672:
0673: suspendedThreads.add(thread);
0674:
0675: super .suspendNotification(thread);
0676: }
0677:
0678: /**
0679: * Resumes notification regarding the specified thread.
0680: * Successive calls to <code>resumeNotification</code>
0681: * without preceding calls to <code>suspendNotification</code>
0682: * will be ignored by the jvmai-system.
0683: *
0684: * @param thread Thread for which to reenable notification.
0685: * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
0686: * @exception NullPointerException <code>thread</code> is <code>null</code>.
0687: */
0688: public void resumeNotification(Thread thread) {
0689: if (!initialized)
0690: throw new NotInitializedException();
0691: if (thread == null)
0692: throw new NullPointerException(
0693: "Parameter `thread' must not be null");
0694:
0695: try {
0696: HotSwapFieldWeaver.commit();
0697: HotSwapClassWeaver.commit();
0698: } finally {
0699: suspendedThreads.remove(thread);
0700: }
0701:
0702: super .resumeNotification(thread);
0703: }
0704:
0705: /**
0706: * Check if the parameters are not null and if this object
0707: * was initialized. If not an exception will be thrown.
0708: *
0709: * @param arg
0710: * @param aopTag
0711: * @throws NotInitializedException this object was not initialized.
0712: * @throws NullPointerException <CODE>arg<CODE> is <CODE>null</CODE>.
0713: * @throws IlligalArgumentExceptin <CODE>aopTag</CODE> is <CODE>null</CODE>.
0714: */
0715: private void checkWatchPrecondition(Object arg, Object aopTag) {
0716: if (!initialized)
0717: throw new NotInitializedException(
0718: "HotSwapAspectInterfaceImpl.setWatch: jvmai not initialized");
0719: if (arg == null)
0720: throw new NullPointerException(
0721: "HotSwapAspectInterfaceImpl.setWatch: null argument parameter");
0722: if (aopTag == null)
0723: throw new IllegalArgumentException(
0724: "HotSwapAspectInterfaceImpl.setWatch: null aopTag value");
0725: }
0726:
0727: /**
0728: * Set `tags[id]' to `tag'. If `tags' is too small then resize it
0729: * appriopriately.
0730: *
0731: * @param tags array holding tags.
0732: * @param tag tag that should be inserted in <CODE>tags</CODE>.
0733: * @param id index at which <CODE>tag</CODE> should be inserted.
0734: * @return the new array for <CODE>tags</CODE>.
0735: */
0736: private Object[] setWatch(Object[] tags, Object tag, int id) {
0737: synchronized (tags) {
0738: if (tags.length < id) {
0739: Object tmp[] = new Object[2 * id];
0740: System.arraycopy(tags, 0, tmp, 0, tags.length);
0741: tags = tmp;
0742: }
0743: if (tags[id] != null)
0744: throw new WatchAlreadySetException("<" + id + ">");
0745: tags[id] = (tag == null) ? aopNullTag : tag;
0746: }
0747: return tags;
0748: }
0749:
0750: /**
0751: * Set `tags[id] = null'. If `id' is out of bounds or the watch already
0752: * cleared a WatchNotSetException is thrown.
0753: *
0754: * @param tags AOP tag array
0755: * @param id Index into `tags'
0756: */
0757: private void clearWatch(Object[] tags, int id) {
0758: synchronized (tags) {
0759: try {
0760: if (tags[id] == null)
0761: throw new WatchNotSetException("<" + id + ">");
0762: tags[id] = null;
0763: } catch (ArrayIndexOutOfBoundsException e) {
0764: throw new WatchNotSetException("<" + id + ">");
0765: }
0766: }
0767: }
0768:
0769: //-----------------------------------------------------------------------------------------------------------------------------
0770: // Callback functions
0771: //-----------------------------------------------------------------------------------------------------------------------------
0772:
0773: /**
0774: * This callback will be invoked at method entry join points. Invocation only
0775: * takes place if the callback is woven in to the corresponding method.
0776: *
0777: * @param methodId method identifier
0778: */
0779: public static final void doOnMethodEntry(int methodId) {
0780: Object aopTag = methodEntryTags[methodId];
0781: Thread currentThread = Thread.currentThread();
0782:
0783: if (hook == null || suspendedThreads.contains(currentThread)
0784: || null == aopTag)
0785: return;
0786:
0787: // Suspend this thread to prevent crosscutting of advice execution
0788: // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0789: suspendedThreads.add(currentThread);
0790:
0791: try {
0792: // there's only one join point of this type, so it
0793: // must be synchronized.
0794: synchronized (methodEntryJoinPoint) {
0795: methodEntryJoinPoint.init(methodId, aopTag);
0796: hook.onMethodEntry(methodEntryJoinPoint);
0797: }
0798: } finally {
0799: // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0800: suspendedThreads.remove(currentThread);
0801: }
0802: // TODO: benchmark if it's faster to generate a new join point object
0803: //hook.onMethodEntry( new HotSwapMethodEntryJoinPointImpl( methodId, aopTag) );
0804: }
0805:
0806: /**
0807: * This callback will be invoked at method exit join points. Invocation only
0808: * takes place if the callback is woven in to the corresponding method.
0809: *
0810: * @param methodId method identifier
0811: * @param resultSlot index of the result in the local variable table
0812: */
0813: public static final void doOnMethodExit(int methodId, int resultSlot) {
0814: Object aopTag = methodExitTags[methodId];
0815: Thread currentThread = Thread.currentThread();
0816:
0817: if (hook == null || suspendedThreads.contains(currentThread)
0818: || null == aopTag)
0819: return;
0820:
0821: // Suspend this thread to prevent crosscutting of advice execution
0822: // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0823: suspendedThreads.add(currentThread);
0824:
0825: try {
0826: // there's only one join point of this type, so it
0827: // must be synchronized.
0828: synchronized (methodExitJoinPoint) {
0829: methodExitJoinPoint.init(methodId, aopTag, resultSlot);
0830: hook.onMethodExit(methodExitJoinPoint);
0831: }
0832: } finally {
0833: // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0834: suspendedThreads.remove(currentThread);
0835: }
0836:
0837: // TODO: benchmark if it's faster to generate a new join point object
0838: //hook.onMethodExit( new HotSwapMethodEntryJoinPointImpl( methodId, aopTag, resultSlot ) );
0839: }
0840:
0841: /**
0842: * This callback will be invoked at constructor join points. Invocation only
0843: * takes place if the callback is woven in to the corresponding constructor.
0844: *
0845: * @param methodId method identifier
0846: */
0847: public static final void doOnConstructor(
0848: /*Object this0,*/int methodId) {
0849: Object aopTag = constructorTags[methodId];
0850: Thread currentThread = Thread.currentThread();
0851:
0852: if (hook == null || suspendedThreads.contains(currentThread)
0853: || null == aopTag)
0854: return;
0855:
0856: // Suspend this thread to prevent crosscutting of advice execution
0857: // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0858: suspendedThreads.add(currentThread);
0859:
0860: try {
0861: // there's only one join point of this type, so it
0862: // must be synchronized.
0863: synchronized (constructorJoinPoint) {
0864: constructorJoinPoint.init(null /*this0*/, methodId,
0865: aopTag);
0866: hook.onConstructor(constructorJoinPoint);
0867: }
0868: } finally {
0869: // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0870: suspendedThreads.remove(currentThread);
0871: }
0872:
0873: // TODO: benchmark if it's faster to generate a new join point object
0874: //hook.onConstructor( new HotSwapMethodEntryJoinPointImpl( this0, methodId, aopTag) );
0875: }
0876:
0877: /**
0878: * This callback will be invoked at field access join points. Invocation only
0879: * takes place if the callback is woven in to the corresponding method.
0880: *
0881: * @param owner object that contains the field
0882: * @param fieldId field identifier
0883: */
0884: public static final void doOnFieldAccess(Object owner, int fieldId) {
0885: //System.out.println("HotSwapAspectInterfaceImpl.doOnFieldAccess(" + owner + "," + fieldId + ")");
0886: Object aopTag = fieldAccessTags[fieldId];
0887: Thread currentThread = Thread.currentThread();
0888:
0889: if (hook == null || suspendedThreads.contains(currentThread)
0890: || null == aopTag)
0891: return;
0892:
0893: // Suspend this thread to prevent crosscutting of advice execution
0894: // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0895: suspendedThreads.add(currentThread);
0896:
0897: try {
0898: // there's only one join point of this type, so it
0899: // must be synchronized.
0900: synchronized (fieldAccessJoinPoint) {
0901: fieldAccessJoinPoint.init(aopTag, fieldId, owner);
0902: hook.onFieldAccess(fieldAccessJoinPoint);
0903: }
0904: } finally {
0905: // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0906: suspendedThreads.remove(currentThread);
0907: }
0908:
0909: // TODO: benchmark if it's faster to generate a new join point object
0910: //hook.onFieldAccess( new HotSwapMethodEntryJoinPointImpl( aopTag, fieldId, owner ) );
0911: }
0912:
0913: /**
0914: * This callback will be invoked at field modification join points. Invocation only
0915: * takes place if the callback is woven in to the corresponding method.
0916: *
0917: * @param owner object that contains the field
0918: * @param fieldId field identifier
0919: * @param slot index of the local variable that contains the new value for the field
0920: */
0921: public static final void doOnFieldModification(Object owner,
0922: int fieldId, int slot) {
0923: //System.out.println("HotSwapAspectInterfaceImpl.doOnFieldModification(" + owner + "," + fieldId + "," + slot + ")");
0924: Object aopTag = fieldModificationTags[fieldId];
0925: Thread currentThread = Thread.currentThread();
0926:
0927: if (hook == null || suspendedThreads.contains(currentThread)
0928: || null == aopTag)
0929: return;
0930:
0931: // Suspend this thread to prevent crosscutting of advice execution
0932: // 1) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0933: suspendedThreads.add(currentThread);
0934:
0935: try {
0936: // there's only one join point of this type, so it
0937: // must be synchronized.
0938: synchronized (fieldModificationJoinPoint) {
0939: fieldModificationJoinPoint.init(aopTag, slot, fieldId,
0940: owner);
0941: hook.onFieldModification(fieldModificationJoinPoint);
0942: }
0943: } finally {
0944: // 2) Note: Comment 1) 'suspendThread' and 2) 'resumeThread' in order to allow crosscuting of aspects
0945: suspendedThreads.remove(currentThread);
0946: }
0947:
0948: // TODO: benchmark if it's faster to generate a new join point object
0949: //hook.onFieldModification( new HotSwapMethodEntryJoinPointImpl( aopTag, slot, fieldId, owner ) );
0950: }
0951:
0952: /**
0953: * Called when ever a new class is loaded by the VM.
0954: * @param cls the new class.
0955: */
0956: public static void doOnClassLoad(Class cls) {
0957: if (null != hook) {
0958: // 1. Notify JoinPointManager
0959: hook.onClassLoad(cls);
0960: }
0961: // 2. Notify HotSwapClassRegister (scanns the class if required)
0962: // may also trigger weaving.
0963: classRegister.classLoaded(cls);
0964: }
0965:
0966: /**
0967: * Called when ever the VM unloads a class.
0968: * This works only with JVMDI, JVMTI has no
0969: * support for unload events.
0970: *
0971: * @param cls
0972: */
0973: public static void doOnClassUnload(Class cls) {
0974: if (null == classRepository)
0975: return;
0976:
0977: // Remove from class file repository.
0978: JavaClass bcelClass = classRepository.findClass(cls.getName());
0979: if (null != bcelClass)
0980: classRepository.removeClass(bcelClass);
0981: // Notify HotSwapClassRegister
0982: //HotSwapClassRegister.getInstance().classUnloaded( cls );
0983: }
0984:
0985: //------------------------------------------------------------------------------
0986: // Utility functions
0987: //------------------------------------------------------------------------------
0988:
0989: /**
0990: * Returns the reflected Method, for a id string containing the class name,
0991: * the method name and it's signature, separated by '#'.
0992: * <P>
0993: * The id string for this method would be <CODE>
0994: * ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver#getMethodFromString#(Ljava/lang/String)Ljava/lang/reflect/Method"
0995: * </CODE>.
0996: * <P>
0997: * Note: The class must declare the method, if it only inherits it from a super
0998: * class, this method will throw an {@link java.lang.NoSuchMethodError
0999: * NoSuchMethodError}.
1000: *
1001: * @param id unique method identification string
1002: * @return Member the reflected object for <CODE>id</CODE> (type is either
1003: * {@link java.lang.reflect.Method} or {@link java.lang.reflect.Constructor}).
1004: * @throws java.lang.ClassNotFoundException can not find the class, declaring the method.
1005: * @throws ch.ethz.jvmai.InvalidIdException id has wrong format (doesn't contain two '#').
1006: * @throws java.lang.NoSuchMethodError can not find the method in the declaring class.
1007: * @throws ch.ethz.jvmai.JVMAIRuntimeException class was not initialized.
1008: */
1009: // id strings are usually generated by HotSwapClassRegister and consumed by the
1010: // various Weavers.
1011: public static Member getMethodFromString(String id)
1012: throws ClassNotFoundException {
1013: if (null == contingencyLoader)
1014: throw new JVMAIRuntimeException("not initialized");
1015:
1016: // 1 Try to get it from cache
1017: Object cachedResult = (Member) resolvedMethods.get(id);
1018: if (null != cachedResult)
1019: return (Member) cachedResult;
1020:
1021: // 2. find the positions of the separators
1022: int sep1 = id.indexOf('#'); // between class name & method name
1023: int sep2 = id.indexOf('#', sep1 + 1); // between method name & signature
1024: int sep3 = id.indexOf('#', sep2 + 1); // indicates a static method (if present)
1025: // Check if the seperators are valid
1026: if (sep1 < 0 || sep2 < 0)
1027: throw new InvalidIdException(
1028: "Invalid method identifier string: " + id);
1029: // 3. get the (sub)strings
1030: Class clazz = Class.forName(id.substring(0, sep1).replace('/',
1031: '.'), true, contingencyLoader);
1032: String methodName = id.substring(sep1 + 1, sep2);
1033: // 4. get the method object
1034: Member result;
1035: if (-1 == sep3) { // non static method
1036: String signature = id.substring(sep2 + 1);
1037: result = getMethodFromStrings(clazz, methodName, signature,
1038: false);
1039: } else { // static method
1040: String signature = id.substring(sep2 + 1, sep3);
1041: result = getMethodFromStrings(clazz, methodName, signature,
1042: true);
1043: }
1044: // 5. cache it.
1045: resolvedMethods.put(id, result);
1046: return result;
1047: }
1048:
1049: /**
1050: * Returns the reflected Method, for a id string containing the class name,
1051: * the method name and it's signature, separated by '#'.
1052: * <P>
1053: * The id string for this method would be <CODE>
1054: * ch.ethz.inf.iks.jvmai.jvmdi.HotSwapClassWeaver#getMethodFromString#(Ljava/lang/String)Ljava/lang/reflect/Method"
1055: * </CODE>.
1056: * <P>
1057: * Note: The class must declare the method, if it only inherits it from a super
1058: * class, this method will throw an {@link java.lang.NoSuchMethodError
1059: * NoSuchMethodError}.
1060: *
1061: * @param className String holding the full qualified name of the class.
1062: * @param methodName String holding the methods name.
1063: * @param signature String holding the methods signature.
1064: * @param isStatic <CODE>true</CODE> if the method is static.
1065: * @return Member the reflected Method or Constructor object.
1066: * @throws java.lang.ClassNotFoundException can not find the class, declaring the method.
1067: * @throws ch.ethz.jvmai.InvalidIdException id has wrong format (doesn't contain two '#').
1068: * @throws java.lang.NoSuchMethodError can not find the method in the declaring class.
1069: * @throws ch.ethz.jvmai.JVMAIRuntimeException class was not initialized.
1070: */
1071: public static Member getMethodFromString(String className,
1072: String methodName, String signature, boolean isStatic)
1073: throws ClassNotFoundException {
1074: if (null == contingencyLoader)
1075: throw new JVMAIRuntimeException("not initialized");
1076: // 1. Try to get it from cache
1077: String key = className + '#' + methodName + '#' + signature
1078: + (isStatic ? "#" : "");
1079: Object cachedResult = resolvedMethods.get(key);
1080: if (null != cachedResult)
1081: return (Member) cachedResult;
1082: // 2. Resolve the class
1083: Class clazz = Class.forName(className.replace('/', '.'), true,
1084: contingencyLoader);
1085: // 3. Get the method object
1086: Member result = getMethodFromStrings(clazz, methodName,
1087: signature, isStatic);
1088: // 4. Cache it.
1089: resolvedMethods.put(key, result);
1090: return result;
1091: }
1092:
1093: /**
1094: * Returns the reflected Field, for a id string containing the class name,
1095: * the field name and it's signature separated by '#'.
1096: * <P>
1097: * Note: The class must declare the field, if it only inherits it from a super
1098: * class, this method will throw an {@link java.lang.NoSuchFieldException
1099: * NoSuchFieldException}.
1100: *
1101: * @param id String holding an unique identiefier for the field.
1102: * @param isStatic <CODE>true</CODE> if the field is static.
1103: * @return Field
1104: * @throws ClassNotFoundException can not find the class, the field belongs to.
1105: * @throws NoSuchFieldException can not find the field
1106: * @throws InvalidIdException the id string is not well formated.
1107: */
1108: public static Field getFieldFromString(String id, boolean isStatic)
1109: throws ClassNotFoundException, NoSuchFieldException {
1110: if (null == contingencyLoader)
1111: throw new JVMAIRuntimeException("not initialized");
1112: // 1. try to get it from cache
1113: Object cachedResult = resolvedFields.get(id);
1114: if (null != cachedResult)
1115: return (Field) cachedResult;
1116:
1117: // 2. Find the position of the separator
1118: // In most cases the full class name is longer as the simple
1119: // field name, so it's faster to search from the end to the beginning.
1120: int sep1 = id.indexOf('#');
1121: int sep2 = id.lastIndexOf('#');
1122: if (sep1 >= sep2 || sep1 < 0)
1123: throw new InvalidIdException(
1124: "Invalid field identifier string: " + id);
1125:
1126: // 3. Get the substrings
1127: String className = id.substring(0, sep1);
1128: String fieldName = id.substring(sep1 + 1, sep2);
1129: String signature = id.substring(sep2 + 1);
1130: // 4. Resolve the class
1131: Class clazz = Class.forName(className.replace('/', '.'), true,
1132: contingencyLoader);
1133: // 5. Get the field object
1134: Field result = getFieldFromStrings(clazz, fieldName, signature,
1135: isStatic);
1136: // 6. Cache the result
1137: resolvedFields.put(id, result);
1138: return result;
1139: }
1140:
1141: /**
1142: * Returns the reflected Field, for a id string containing the class name,
1143: * the field name and it's signature separated by '#'.
1144: * <P>
1145: * Note: The class must declare the field, if it only inherits it from a super
1146: * class, this method will throw an {@link java.lang.NoSuchFieldException
1147: * NoSuchFieldException}.
1148: *
1149: * @param className String holding the full qualified class name.
1150: * @param fieldName String holding the fields name.
1151: * @param signature String holding the signature (type) of the field.
1152: * @param isStatic <CODE>true</CODE> if the field is static.
1153: * @return Field
1154: * @throws ClassNotFoundException can not find the class, the field belongs to.
1155: * @throws NoSuchFieldException can not find the field
1156: * @throws InvalidIdException the id string is not well formated.
1157: */
1158: public static Field getFieldFromString(String className,
1159: String fieldName, String signature, boolean isStatic)
1160: throws ClassNotFoundException, NoSuchFieldException {
1161: if (null == contingencyLoader)
1162: throw new JVMAIRuntimeException("not initialized");
1163: // 1. Try to get it from cache
1164: String key = className + "#" + fieldName + "#" + signature;
1165: Object cachedResult = resolvedFields.get(key);
1166: if (null != cachedResult)
1167: return (Field) cachedResult;
1168: // 2. Resolve the class
1169: Class clazz = Class.forName(className.replace('/', '.'), true,
1170: contingencyLoader);
1171: // 3. Get the field object
1172: Field result = getFieldFromStrings(clazz, fieldName, signature,
1173: isStatic);
1174: // 4. Cache the field
1175: resolvedFields.put(key, result);
1176: return result;
1177: }
1178:
1179: /**
1180: * Returns a BCEL class of a java class.
1181: *
1182: * @param cls
1183: * @return JavaClass BCEL class for <CODE>cls</CODE>
1184: * @throws JVMAIRuntimeException the class is not initialized, <CODE>startup()</CODE>
1185: * was never invoked.
1186: * @throws ClassNotFoundException can not find the class or the class file
1187: */
1188: public static JavaClass getBCELClassDefinition(Class cls)
1189: throws ClassNotFoundException {
1190: if (null == classRepository)
1191: throw new JVMAIRuntimeException("not initialized");
1192:
1193: return classRepository.loadClass(cls); // throws an exception, if not found
1194: }
1195:
1196: /**
1197: * Returns the original class implementation from a class file
1198: * in CLASS_PATH, if available. This is deprecated use
1199: * {@link #getBCELClassDefinition(Class)} instead.
1200: *
1201: * @param cls Class thats implementation should be returned.
1202: * @return InputStream with the contents of the class file.
1203: * @exception RuntimeException if class file was not found.
1204: * @exception NullPointerException if <CODE>cls</CODE> is <CODE>null</CODE>.
1205: *
1206: * @deprecated
1207: */
1208: public java.io.InputStream getOriginalClassDefinition(Class cls)
1209: throws IOException {
1210: if (null == cls)
1211: throw new NullPointerException();
1212:
1213: java.io.InputStream result;
1214:
1215: // Try to get the definition from the cache
1216: Object classCache = classFileMap.get(cls);
1217: if (null == classCache) {
1218: // Get definition from class file
1219: ClassLoader cl = cls.getClassLoader();
1220: if (cl == null)
1221: cl = contingencyLoader;
1222:
1223: String fileName = cls.getName().replace('.', '/')
1224: + ".class";
1225: result = cl.getResourceAsStream(fileName);
1226:
1227: if (null == result)
1228: throw new JVMAIRuntimeException(
1229: "JVMAspectInterface.getOriginalClassDefinition: could not find classfile "
1230: + cls.getName());
1231:
1232: // Add definition to cache
1233: int fileSize = result.available();
1234: byte[] classDef = new byte[fileSize];
1235:
1236: if (result.markSupported()) {
1237: result.mark(fileSize);
1238: result.read(classDef);
1239: result.reset();
1240: } else {
1241: result.read(classDef);
1242: result = new ByteArrayInputStream(classDef);
1243: }
1244:
1245: classFileMap.put(cls, classDef);
1246: } else
1247: // Definition was in cache, just have to wrap it in a stream.
1248: result = new ByteArrayInputStream((byte[]) classCache);
1249:
1250: return result;
1251: }
1252:
1253: //------------------------------------------------------------------------------
1254: // Native methods
1255: //------------------------------------------------------------------------------
1256:
1257: /**
1258: * Returns a reflected method object for a method identified by
1259: * it's name and signature.
1260: * <P>
1261: * This is a native function because some (synthetic) methods may not be
1262: * accessed via the Java reflection API (and this should also be faster).
1263: *
1264: * @param className name of a class holding the method (all classes containing
1265: * this method are valid, not only the declaring class)
1266: * @param methodName name of the method
1267: * @param signature method's signature.
1268: * @param isStatic <CODE>true</CODE> if the method is a static class member.
1269: * @return Member reflected object representing the method, may either be
1270: * of type {@link java.lang.reflected.Method java.lang.reflected.Method}
1271: * or {@link java.lang.reflected.Constructor java.lang.reflected.Constructor}.
1272: */
1273: private static native Member getMethodFromStrings(Class clazz,
1274: String methodName, String signature, boolean isStatic);
1275:
1276: /**
1277: * Returns a reflected field object for a field identified by
1278: * it's name and signature.
1279: * <P>
1280: * This is a native function because some fields may not be
1281: * accessed via the Java reflection API (and this should also be faster).
1282: *
1283: * @param className name of a class holding the field (all classes containing
1284: * this method are valid, not only the declaring class)
1285: * @param fieldName name of the field
1286: * @param signature the signature of the field (type).
1287: * @param isStatic <CODE>true</CODE> if the field is a static class member.
1288: * @return Field reflected object representing the field.
1289: */
1290: private static native Field getFieldFromStrings(Class clazz,
1291: String fieldName, String signature, boolean isStatic);
1292:
1293: /// initializes the native part of this class.
1294: private native void doStartUp(String[] prefixes, boolean openWorld);
1295: }
1296:
1297: //======================================================================
1298: //
1299: //$Log$
1300: //
|