001: //
002: // This file is part of the prose package.
003: //
004: // The contents of this file are subject to the Mozilla Public License
005: // Version 1.1 (the "License"); you may not use this file except in
006: // compliance with the License. You may obtain a copy of the License at
007: // http://www.mozilla.org/MPL/
008: //
009: // Software distributed under the License is distributed on an "AS IS" basis,
010: // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: // for the specific language governing rights and limitations under the
012: // License.
013: //
014: // The Original Code is prose.
015: //
016: // The Initial Developer of the Original Code is Andrei Popovici. Portions
017: // created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
018: // All Rights Reserved.
019: //
020: // Contributor(s):
021: // $Id: MethodCut.java,v 1.3 2004/05/12 09:41:55 anicoara Exp $
022: // =====================================================================
023: //
024: // (history at end)
025: //
026:
027: package ch.ethz.prose.crosscut;
028:
029: // used packages
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.util.Arrays;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Vector;
036:
037: import ch.ethz.jvmai.JoinPoint;
038: import ch.ethz.prose.engine.JoinPointRequest;
039: import ch.ethz.jvmai.MethodEntryJoinPoint;
040: import ch.ethz.jvmai.MethodExitJoinPoint;
041: import ch.ethz.prose.filter.ANDingPointCutter;
042: import ch.ethz.prose.filter.PointCutter;
043:
044: /**
045: * Class MethodCut represents a crosscut. Such a crosscut
046: * defines a pattern (for matching specific join-points) and a method
047: * to be executed. Users must subclass <code>MethodCut</code>.
048: * There are two main modalities for subclassing:
049: * <h3>The tipical way (normal user)</h3>
050: * Define exactly one method (e.g., <code>METHOD_ARGS(Bar thisO,Baz param1)</code>).
051: * This method is both the advice action to be executed and it defines
052: * a pattern. Thus, just entries and exits of invocations of the form
053: * <code>Bar.*(Baz)</code> will be considered join-points of this
054: * crosscut.
055: * <p>
056: * This crosscut defines a crosscut for all entry- and exit-
057: * points of the matched methods.
058: * <p>
059: * Use <code>poointCutter</code> to further restrict the number of
060: * points were advices are executed.
061: *
062: * @version $Revision: 1.3 $
063: * @author Andrei Popovici
064: */
065: public abstract class MethodCut extends AbstractCrosscut implements
066: java.io.Serializable {
067:
068: ///////////////////////////////////////////////////////////////////////////////////////////
069: /// THE CROSSCUT: ADVICE METHOD + ADVICE EXECUTION put together
070: ///////////////////////////////////////////////////////////////////////////////////////////
071:
072: /** Override the value of this variable if you want to change the
073: * name of the method wildcards. Currently, a method-name mathcing
074: * everything should have the name <code>METHOD_ARGS</code>
075: */
076: public void METHOD_ARGS() {
077: }
078:
079: /** If you have more than one method in this class, determining the
080: * name of the advice method will use the value of this method. This
081: * variable should then be initialized with the name of the method
082: * you want to call as advice method.
083: */
084:
085: transient boolean isInitialized = false;
086: transient MethodCutSpecializer mcutSpecializer = null;
087: transient MethodCutSignaturePattern adviceSignature = null;
088: String toStringSignature;
089:
090: private void initState() throws MissingInformationException {
091: if (isInitialized)
092: return;
093: isInitialized = true;
094:
095: adviceSignature = new MethodCutSignaturePattern(this );
096: mcutSpecializer = new MethodCutSpecializer(adviceSignature);
097:
098: toStringSignature = adviceSignature.toString();
099: }
100:
101: /** We want people to subclass this class.
102: * Create a <code>MethodCut</code> object.
103: *
104: * @throws MissingInformationException this crosscut does
105: * not define an advice method / or does not override methodAdvice.
106: *
107: */
108: protected MethodCut() throws MissingInformationException {
109: initState();
110: }
111:
112: public void insertionAction(boolean beforeInsertion) {
113: super .insertionAction(beforeInsertion);
114:
115: // we might provide an initstate here for the case
116: // this crosscut is deserialized and the
117: // static initializer or the constructor are not properly
118: // called
119: initState();
120: }
121:
122: /**
123: * Return all potential classes to which this crosscut applies:
124: * To all loaded classes, apply the <code>isPotentialCrosscutClass</code>
125: * selector.
126: */
127: protected Class[] potentialCrosscutClasses()
128: throws MissingInformationException {
129: // get exactly one method declared in this class with more
130: // than one argument
131:
132: Class[] result = new Class[] {};
133: List searchList = new Vector(Arrays.asList(super
134: .potentialCrosscutClasses()));
135:
136: // if the receiver class is not a wildcard, we add the
137: // receiver class to the potential crosscut classes
138: Class receiverClass = adviceSignature.getReceiverType();
139: if (receiverClass != null
140: && !Wildcard.class.isAssignableFrom(receiverClass)
141: && !searchList.contains(receiverClass))
142: searchList.add(receiverClass);
143: Vector resultList = new Vector();
144:
145: // then we search in the search list
146: Iterator i = searchList.iterator();
147: while (i.hasNext()) {
148: Class crtCls = (Class) i.next();
149: if (isPotentialCrosscutClass(crtCls))
150: resultList.add(crtCls);
151: }
152:
153: // and return the corresponding array
154: result = (Class[]) resultList.toArray(new Class[] {});
155: return result;
156: }
157:
158: /** Return true only if
159: *
160: * <ol>
161: * <li> This crosscut redefines the <code>methodAdvice</code> method, <em>OR</em>
162: * <li> if this crosscut defines an advice, and the corresponding <code>UserDefinedMCSignature</code>
163: * matches the target class <code>crtCls</code>.
164: * </ol>
165: */
166: protected boolean isPotentialCrosscutClass(Class crtCls)
167: throws MissingInformationException {
168: return adviceSignature.matchesTarget(crtCls);
169: }
170:
171: /**
172: * Retrieve those methods belonging to <code>theClass</code>
173: * which have the same signature as the advice methods. Use the
174: * <code>UserDefinedMCSignature</code> object (<code>adviceSignature</code>)
175: * to determine which methods defined in class <code>theClass</code>
176: * match the pattern.
177: * (if wildcards
178: * are present, they use them to match more methods in <code>theClass</code>)
179: * <p>
180: * Return a list of <code>JoinPointRequest</code> objects corresponding
181: * to all locations of the matched methods.
182: * <p>
183: * <em>This implementation will return just Method-Entry and -Exit
184: * locations.</em>.
185: */
186: protected CrosscutRequest doCreateRequest(Class theClass) {
187: //1. retrieve those methods TCM belonging to class theClass
188: // for which the following holds:
189: // if M[i] is not a wildcard, M[i] is assignable from TCM[i]
190: // if M[i] is a wildcard, TCM[i] matches M[i] or
191: // TCM[i..TCM.lenth] matches M[i]
192: CrosscutRequest result = new CrosscutRequest();
193:
194: //take the methods declared in the given class only (ignore
195: //inherited methods!)
196: //A possible problem might occur because of the access control
197: Method[] methArray = null;
198:
199: try {
200: methArray = theClass.getDeclaredMethods();
201: } catch (NoClassDefFoundError e) {
202: return result;
203: }
204:
205: for (int i = 0; i < methArray.length; i++) {
206: Class[] params = methArray[i].getParameterTypes();
207: JoinPointRequest crtRequest;
208:
209: crtRequest = requestFactory.createJoinPointRequest(
210: MethodEntryJoinPoint.KIND, methArray[i]);
211: if (mcutSpecializer.isSpecialRequest(crtRequest))
212: result.add(crtRequest);
213:
214: crtRequest = requestFactory.createJoinPointRequest(
215: MethodExitJoinPoint.KIND, methArray[i]);
216: if (mcutSpecializer.isSpecialRequest(crtRequest))
217: result.add(crtRequest);
218: }
219:
220: return result;
221: }
222:
223: /**
224: * Create an action to execute the advice which matched the
225: * method in which the location of <code>jpe</code> resides.
226: *
227: * @exception InvocationTargetException some error occured inside
228: * the advice method.
229: * @exception IllegalAccessException the advice method was not public
230: */
231: public void joinPointAction(MethodEntryJoinPoint ev)
232: throws IllegalAccessException, InvocationTargetException {
233: methodAdvice(ev);
234: }
235:
236: /**
237: * Create an action to execute the advice which matched the
238: * method in which the location of <code>jpe</code> resides.
239: *
240: * @exception InvocationTargetException some error occured inside
241: * the advice method.
242: * @exception IllegalAccessException the advice method was not public
243: */
244: public void joinPointAction(MethodExitJoinPoint ev)
245: throws IllegalAccessException, InvocationTargetException {
246: // call advice
247: methodAdvice(ev);
248: }
249:
250: /** If 'methodAdvice' has been redefined, then we will deal with a
251: * 'DefaultMcutSignature'. But in THAT case, this method
252: * will be never executed.
253: *
254: */
255: private void methodAdvice(JoinPoint joinPoint)
256: throws InvocationTargetException, IllegalAccessException {
257:
258: // create the appropriate 'adviceExecutionObject';
259: McutAdvice toRun = null;
260: switch (adviceSignature.signatureCathegory) {
261: case SignaturePattern.SIGNATURE__EMPTY:
262: METHOD_ARGS();
263: return; //BUGFIX: //break
264: case SignaturePattern.SIGNATURE__CONCRETE__CONCRETE:
265: toRun = new ConcreteConcreteMcutAdvice(this , joinPoint,
266: (MethodCutSignaturePattern) adviceSignature);
267: break;
268: case SignaturePattern.SIGNATURE__WILDCARD__CONCRETE:
269: toRun = new WildcardConcreteMcutAdvice(this , joinPoint,
270: (MethodCutSignaturePattern) adviceSignature);
271: break;
272: case SignaturePattern.SIGNATURE__WILDCARD__WILDCARD:
273: toRun = new WildcardWildcardMcutAdvice(this , joinPoint,
274: (MethodCutSignaturePattern) adviceSignature);
275: break;
276: case SignaturePattern.SIGNATURE__CONCRETE__WILDCARD:
277: toRun = new ConcreteWildcardMcutAdvice(this , joinPoint,
278: (MethodCutSignaturePattern) adviceSignature);
279: break;
280: default:
281: toRun = new DefaultMcutAdvice(this , joinPoint,
282: (MethodCutSignaturePattern) adviceSignature);
283: break;
284: }
285:
286: toRun.execute();
287:
288: }
289:
290: public PointCutter equivalentSpecializer() {
291: initState();
292: if (getSpecializer() == null)
293: return mcutSpecializer;
294: else
295: return new ANDingPointCutter(mcutSpecializer,
296: (PointCutter) getSpecializer());
297: }
298:
299: /**
300: * Get advice method, i.e. <code>METHOD_ARGS(...)</code>. The advice
301: * method is used by the full code weaver.
302: *
303: * @return advice method
304: */
305: public Method getMethod() {
306: return adviceSignature.methodObj;
307: }
308:
309: public String toString() {
310: return " Crosscut: 'MethodCut' \n" + " Advice:"
311: + toStringSignature + "\n" + " PointCutter: "
312: + getSpecializer() + "\n";
313: }
314: }
315:
316: //======================================================================
317: //
318: // $Log: MethodCut.java,v $
319: // Revision 1.3 2004/05/12 09:41:55 anicoara
320: // Remove the README.RVM file
321: //
322: // Revision 1.2 2003/07/11 12:27:43 apopovic
323: // Bug fix for rare cases. Some classed loaded late may throw a 'NoClassDefError' when
324: // trying to retrieve the declared methods; The crosscut for such cases is now an empty listt
325: //
326: // Revision 1.1.1.1 2003/07/02 15:30:51 apopovic
327: // Imported from ETH Zurich
328: //
329: // Revision 1.4 2003/05/26 13:28:52 popovici
330: // Documentation Improvements
331: //
332: // Revision 1.3 2003/05/25 11:46:45 popovici
333: // Improved 'toString' presentation of aspects
334: //
335: // Revision 1.2 2003/05/05 17:57:45 popovici
336: // New cflow below pointcuter added; MethodCut fixed for usage in Cflow below (used not to be initialized once transported over the network)
337: //
338: // Revision 1.1 2003/05/05 13:58:11 popovici
339: // renaming from runes to prose
340: //
341: // Revision 1.18 2002/06/05 09:27:59 popovici
342: // thisJoinPoint() introduced in Abstract Crosscut and subclasses;
343: //
344: // Revision 1.17 2002/06/04 11:53:57 popovici
345: // Small refactorization: the DoNothingMatchAll UserDefinedMCSignature class src/ch/ethz/inf/runes/crosscut/MethodCut.java
346: // introduced to modell previous 'MethodCut' behavior. Class commented
347: //
348: // Revision 1.16 2002/06/03 13:11:02 popovici
349: // adviceSignature.methodObj.getParameterTypes() inlined
350: //
351: // Revision 1.15 2002/06/03 12:48:15 popovici
352: // renaming of the inner classes, objects, etc.
353: //
354: // Revision 1.14 2002/06/03 12:16:33 popovici
355: // heavy bug fixes of the Advice/Execution inner class structure
356: //
357: // Revision 1.13 2002/05/31 12:24:12 popovici
358: // methodAdvice simplified. Code moved to 5 inner classes
359: // of type 'McutAdvice'
360: //
361: // Revision 1.12 2002/05/31 09:00:11 popovici
362: // Bug fix in AdviceMehtod.matchSignature; reindentation
363: //
364: // Revision 1.11 2002/05/31 08:25:22 popovici
365: // Inner class 'Advice Method' creted.
366: //
367: // Revision 1.10 2002/05/30 15:37:15 popovici
368: // refactorization of 'doCreateCrosscut'. Usage of the
369: // newly introduced isGenericAssignable.
370: //
371: // Revision 1.9 2002/05/30 13:55:36 popovici
372: // doCreateCrosscut contained an (aparently) useless
373: // condition.
374: //
375: // Revision 1.8 2002/05/30 09:54:18 popovici
376: // 'isGeneric assignable' extracted from potentialCrosscutClasses
377: //
378: // Revision 1.7 2002/03/28 13:48:43 popovici
379: // Mozilla-ified
380: //
381: // Revision 1.6 2002/03/06 13:48:38 popovici
382: // joinPointAction now in 4 flavours, depending on the join point type
383: //
384: // Revision 1.5 2002/02/21 14:19:24 popovici
385: // Minor bug fix, rvm considers local variables too
386: //
387: // Revision 1.4 2002/02/21 12:39:20 popovici
388: // Crosscut efficiency issues:
389: // - joinPointAction dispatch based on static optimization
390: // (->doesEventSpecialization, 'setSpecializer' modified)
391: // (->calculation of 'adviceMethodOptimization', in Func.Crossc)
392: // - joinPointAction now uses JoinPoints (not Events)
393: // - JoinPointListeners (including crosscuts) now use joinPointReached(XXXJoinPoint) to avoid casting
394: // Crosscut architectural issues:
395: // - AbstractCrosscut now insertable.
396: // - AbstractCrosscuts owns referecnces to JVMAI
397: //
398: // Revision 1.3 2002/02/05 09:57:55 smarkwal
399: // JVMDI-specific code replaced by JVMAI. Prose-implementation classes and reflection package removed.
400: //
401: // Revision 1.1.1.1 2001/11/29 18:13:17 popovici
402: // Sources from runes
403: //
404: // Revision 1.1.2.18 2001/11/21 11:56:27 popovici
405: //
406: // -The sun.tools.agent and ch.ethz.inf.util.JVMDIUtil functionality
407: // replaced with the iks.jvmdi package. References to this old
408: // functionality replaced throughout the code.
409: // -Partial reimplementation of the ch.ethz.inf.iks.runes classes,
410: // part of their functionality moved to the ch.ethz.prose.reflect
411: // abstract classes. New classes and functionality added to the
412: // ch.ethz.prose.reflect package, partially to reflect the
413: // more stable features taken from the iks.runes packages, partially
414: // to reflect the structure of the VM (constant pool, etc). Functionality in
415: // ch.ethz.prose.crosscut and the junit classes adapted to use the
416: // new form of the ch.ethz.prose.reflect package
417: //
418: // Revision 1.1.2.17 2001/09/24 16:29:49 popovici
419: // demo errors removed
420: //
421: // Revision 1.1.2.16 2001/07/15 13:08:16 popovici
422: // Reimplemented using the 'isPotentialCrosscutClass' template method.
423: //
424: // Revision 1.1.2.15 2001/06/01 12:16:30 popovici
425: // Feature 'fix'. End-of-method location is now added to the join-point-
426: // requests only if it is different from the entry location.
427: //
428: // Revision 1.1.2.14 2001/05/21 12:31:43 popovici
429: // Bug fix: the last modification of the 'potentialCrosscutClasses' had
430: // induced a bug: the actual matching class, if not loaded, would not
431: // belong to the crosscut. Of course, the crosscut should take care
432: // at least to load the receiver class. This is now done.
433: //
434: // Revision 1.1.2.13 2001/05/17 12:18:09 popovici
435: // Important: Implementation and specification change. The advice method
436: // used to perform an *exact match* on the first argument. This condition
437: // is now relaxed. Thus, a 'Remote' in the as a first argument of this method
438: // selects all classes inheriting remote. This change improves dramatically
439: // insertion speed.
440: //
441: // Revision 1.1.2.12 2001/03/15 08:14:29 mrmuller
442: // minor change in logging
443: //
444: // Revision 1.1.2.11 2001/02/21 13:31:43 popovici
445: // Specialization of the 'toString' method to show method advice too.
446: //
447: // Revision 1.1.2.10 2001/02/13 18:42:11 popovici
448: // Bug fix: for advice signatures like '(ANY)' the code used
449: // to match everything
450: //
451: // Revision 1.1.2.9 2001/02/13 15:13:26 mrmuller
452: // Native methods excluded from functional crosscut
453: //
454: // Revision 1.1.2.8 2001/02/07 11:51:39 popovici
455: // Initial Revision
456: //
457: // Revision 1.1.2.7 2001/01/18 14:22:20 popovici
458: // Implementation of 'localActionImpl' changed in order to avoid
459: // costly Vector.addAll operations. The special-case 'this' variable is
460: // now taken care of outside the main loop
461: //
462: // Revision 1.1.2.6 2001/01/18 13:07:01 groos
463: // - doCreateRequest() modified to take all *declared* methods of
464: // the given class instead of all public methods (incl. inherited
465: // methods)
466: //
467: // Revision 1.1.2.5 2000/12/01 09:24:32 popovici
468: // Bug fixes:
469: // 1. Crosscut does not cut accross abstract methods
470: // 2. Advice method now callable even if in inner class
471: // 3. Documentation added
472: //
473: // Revision 1.1.2.4 2000/11/15 15:15:32 popovici
474: // joinPointAction throws now IllegalAccessException too
475: //
476: // Revision 1.1.2.3 2000/10/30 17:28:57 groos
477: // documentation updates
478: //
479: // Revision 1.1.2.2 2000/10/25 09:09:07 popovici
480: // Bug fixed in 'localActionImpl': 'REST' did not match empty lists
481: // of parameters (exception triggered before check). Fixed.
482: //
483: // Revision 1.1.2.1 2000/10/23 18:36:37 popovici
484: // Initial Revision
485: //
|