KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > prose > crosscut > MethodCut


1 //
2
// This file is part of the prose package.
3
//
4
// The contents of this file are subject to the Mozilla Public License
5
// Version 1.1 (the "License"); you may not use this file except in
6
// compliance with the License. You may obtain a copy of the License at
7
// http://www.mozilla.org/MPL/
8
//
9
// Software distributed under the License is distributed on an "AS IS" basis,
10
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
// for the specific language governing rights and limitations under the
12
// License.
13
//
14
// The Original Code is prose.
15
//
16
// The Initial Developer of the Original Code is Andrei Popovici. Portions
17
// created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
18
// All Rights Reserved.
19
//
20
// Contributor(s):
21
// $Id: MethodCut.java,v 1.3 2004/05/12 09:41:55 anicoara Exp $
22
// =====================================================================
23
//
24
// (history at end)
25
//
26

27 package ch.ethz.prose.crosscut;
28
29
30
31 // used packages
32
import java.io.Serializable JavaDoc;
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35 import java.lang.reflect.Modifier JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Vector JavaDoc;
41
42 import ch.ethz.jvmai.ExceptionJoinPoint;
43 import ch.ethz.jvmai.FieldAccessJoinPoint;
44 import ch.ethz.jvmai.FieldModificationJoinPoint;
45 import ch.ethz.jvmai.JoinPoint;
46 import ch.ethz.prose.engine.JoinPointRequest;
47 import ch.ethz.jvmai.MethodEntryJoinPoint;
48 import ch.ethz.jvmai.MethodExitJoinPoint;
49 import ch.ethz.prose.engine.MethodEntryRequest;
50 import ch.ethz.prose.engine.MethodExitRequest;
51 import ch.ethz.inf.util.Logger;
52 import ch.ethz.prose.filter.ANDingPointCutter;
53 import ch.ethz.prose.filter.PointCutter;
54
55 /**
56  * Class MethodCut represents a crosscut. Such a crosscut
57  * defines a pattern (for matching specific join-points) and a method
58  * to be executed. Users must subclass <code>MethodCut</code>.
59  * There are two main modalities for subclassing:
60  * <h3>The tipical way (normal user)</h3>
61  * Define exactly one method (e.g., <code>METHOD_ARGS(Bar thisO,Baz param1)</code>).
62  * This method is both the advice action to be executed and it defines
63  * a pattern. Thus, just entries and exits of invocations of the form
64  * <code>Bar.*(Baz)</code> will be considered join-points of this
65  * crosscut.
66  * <p>
67  * This crosscut defines a crosscut for all entry- and exit-
68  * points of the matched methods.
69  * <p>
70  * Use <code>poointCutter</code> to further restrict the number of
71  * points were advices are executed.
72  *
73  * @version $Revision: 1.3 $
74  * @author Andrei Popovici
75  */

76 public
77 abstract class MethodCut extends AbstractCrosscut implements java.io.Serializable JavaDoc {
78
79     ///////////////////////////////////////////////////////////////////////////////////////////
80
/// THE CROSSCUT: ADVICE METHOD + ADVICE EXECUTION put together
81
///////////////////////////////////////////////////////////////////////////////////////////
82

83   /** Override the value of this variable if you want to change the
84    * name of the method wildcards. Currently, a method-name mathcing
85    * everything should have the name <code>METHOD_ARGS</code>
86    */

87     public void METHOD_ARGS(){}
88
89     /** If you have more than one method in this class, determining the
90      * name of the advice method will use the value of this method. This
91      * variable should then be initialized with the name of the method
92      * you want to call as advice method.
93      */

94
95
96     transient boolean isInitialized = false;
97     transient MethodCutSpecializer mcutSpecializer = null;
98     transient MethodCutSignaturePattern adviceSignature = null;
99     String JavaDoc toStringSignature;
100
101     private void initState() throws MissingInformationException
102     {
103         if (isInitialized) return;
104         isInitialized=true;
105     
106         adviceSignature = new MethodCutSignaturePattern(this);
107         mcutSpecializer = new MethodCutSpecializer(adviceSignature);
108     
109         toStringSignature = adviceSignature.toString();
110     }
111
112     /** We want people to subclass this class.
113      * Create a <code>MethodCut</code> object.
114      *
115      * @throws MissingInformationException this crosscut does
116      * not define an advice method / or does not override methodAdvice.
117      *
118      */

119     protected MethodCut() throws MissingInformationException
120     {
121         initState();
122     }
123
124     public void insertionAction(boolean beforeInsertion)
125     {
126         super.insertionAction(beforeInsertion);
127     
128         // we might provide an initstate here for the case
129
// this crosscut is deserialized and the
130
// static initializer or the constructor are not properly
131
// called
132
initState();
133     }
134
135
136     /**
137      * Return all potential classes to which this crosscut applies:
138      * To all loaded classes, apply the <code>isPotentialCrosscutClass</code>
139      * selector.
140      */

141     protected Class JavaDoc[] potentialCrosscutClasses() throws MissingInformationException
142     {
143       // get exactly one method declared in this class with more
144
// than one argument
145

146       Class JavaDoc[] result = new Class JavaDoc[]{};
147       List JavaDoc searchList = new Vector JavaDoc(Arrays.asList(super.potentialCrosscutClasses()));
148
149       // if the receiver class is not a wildcard, we add the
150
// receiver class to the potential crosscut classes
151
Class JavaDoc receiverClass=adviceSignature.getReceiverType();
152       if (receiverClass!= null && !Wildcard.class.isAssignableFrom(receiverClass) &&
153           !searchList.contains(receiverClass))
154         searchList.add(receiverClass);
155       Vector JavaDoc resultList = new Vector JavaDoc();
156
157       // then we search in the search list
158
Iterator JavaDoc i = searchList.iterator();
159       while (i.hasNext())
160       {
161           Class JavaDoc crtCls=(Class JavaDoc)i.next();
162           if (isPotentialCrosscutClass(crtCls))
163             resultList.add(crtCls);
164       }
165
166       // and return the corresponding array
167
result = (Class JavaDoc[])resultList.toArray(new Class JavaDoc[]{});
168       return result;
169     }
170
171   /** Return true only if
172    *
173    * <ol>
174    * <li> This crosscut redefines the <code>methodAdvice</code> method, <em>OR</em>
175    * <li> if this crosscut defines an advice, and the corresponding <code>UserDefinedMCSignature</code>
176    * matches the target class <code>crtCls</code>.
177    * </ol>
178    */

179   protected boolean isPotentialCrosscutClass(Class JavaDoc crtCls) throws MissingInformationException
180   {
181       return adviceSignature.matchesTarget(crtCls);
182   }
183
184   /**
185    * Retrieve those methods belonging to <code>theClass</code>
186    * which have the same signature as the advice methods. Use the
187    * <code>UserDefinedMCSignature</code> object (<code>adviceSignature</code>)
188    * to determine which methods defined in class <code>theClass</code>
189    * match the pattern.
190    * (if wildcards
191    * are present, they use them to match more methods in <code>theClass</code>)
192    * <p>
193    * Return a list of <code>JoinPointRequest</code> objects corresponding
194    * to all locations of the matched methods.
195    * <p>
196    * <em>This implementation will return just Method-Entry and -Exit
197    * locations.</em>.
198    */

199   protected CrosscutRequest doCreateRequest(Class JavaDoc theClass)
200   {
201       //1. retrieve those methods TCM belonging to class theClass
202
// for which the following holds:
203
// if M[i] is not a wildcard, M[i] is assignable from TCM[i]
204
// if M[i] is a wildcard, TCM[i] matches M[i] or
205
// TCM[i..TCM.lenth] matches M[i]
206
CrosscutRequest result = new CrosscutRequest();
207
208       //take the methods declared in the given class only (ignore
209
//inherited methods!)
210
//A possible problem might occur because of the access control
211
Method JavaDoc[] methArray = null;
212
213       try { methArray=theClass.getDeclaredMethods(); }
214       catch (NoClassDefFoundError JavaDoc e)
215       {
216           return result;
217       }
218
219       for(int i=0; i<methArray.length; i++)
220       {
221           Class JavaDoc[] params = methArray[i].getParameterTypes();
222           JoinPointRequest crtRequest;
223     
224           crtRequest = requestFactory.createJoinPointRequest(MethodEntryJoinPoint.KIND,methArray[i]);
225           if (mcutSpecializer.isSpecialRequest(crtRequest))
226               result.add(crtRequest);
227     
228           crtRequest = requestFactory.createJoinPointRequest(MethodExitJoinPoint.KIND,methArray[i]);
229           if (mcutSpecializer.isSpecialRequest(crtRequest))
230               result.add(crtRequest);
231       }
232
233       return result;
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(MethodEntryJoinPoint ev) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc
245   {
246       methodAdvice(ev);
247   }
248
249   /**
250    * Create an action to execute the advice which matched the
251    * method in which the location of <code>jpe</code> resides.
252    *
253    * @exception InvocationTargetException some error occured inside
254    * the advice method.
255    * @exception IllegalAccessException the advice method was not public
256    */

257   public void joinPointAction(MethodExitJoinPoint ev) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc
258   {
259       // call advice
260
methodAdvice(ev);
261   }
262
263
264   /** If 'methodAdvice' has been redefined, then we will deal with a
265    * 'DefaultMcutSignature'. But in THAT case, this method
266    * will be never executed.
267    *
268    */

269   private void methodAdvice(JoinPoint joinPoint)
270     throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc
271     {
272
273       // create the appropriate 'adviceExecutionObject';
274
McutAdvice toRun= null;
275       switch(adviceSignature.signatureCathegory)
276       {
277         case SignaturePattern.SIGNATURE__EMPTY:
278             METHOD_ARGS();
279             break;
280         case SignaturePattern.SIGNATURE__CONCRETE__CONCRETE:
281             toRun = new ConcreteConcreteMcutAdvice(this, joinPoint,(MethodCutSignaturePattern)adviceSignature);
282             break;
283         case SignaturePattern.SIGNATURE__WILDCARD__CONCRETE:
284             toRun = new WildcardConcreteMcutAdvice(this, joinPoint,(MethodCutSignaturePattern)adviceSignature);
285             break;
286         case SignaturePattern.SIGNATURE__WILDCARD__WILDCARD:
287             toRun = new WildcardWildcardMcutAdvice(this, joinPoint,(MethodCutSignaturePattern)adviceSignature);
288             break;
289         case SignaturePattern.SIGNATURE__CONCRETE__WILDCARD:
290             toRun = new ConcreteWildcardMcutAdvice(this, joinPoint,(MethodCutSignaturePattern)adviceSignature);
291             break;
292         default:
293             toRun = new DefaultMcutAdvice(this, joinPoint,(MethodCutSignaturePattern)adviceSignature);
294             break;
295       }
296
297       toRun.execute();
298
299     }
300
301     public PointCutter equivalentSpecializer()
302     {
303         initState();
304         if (getSpecializer() == null)
305             return mcutSpecializer;
306         else
307             return new ANDingPointCutter(mcutSpecializer,(PointCutter)getSpecializer());
308     }
309
310     /**
311      * Get advice method, i.e. <code>METHOD_ARGS(...)</code>. The advice
312      * method is used by the full code weaver.
313      *
314      * @return advice method
315      */

316     public Method JavaDoc getMethod() {
317       return adviceSignature.methodObj;
318     }
319     
320     public String JavaDoc toString()
321     {
322       return " Crosscut: 'MethodCut' \n" +
323          " Advice:" + toStringSignature + "\n" +
324          " PointCutter: " + getSpecializer() + "\n";
325     }
326 }
327
328
329 //======================================================================
330
//
331
// $Log: MethodCut.java,v $
332
// Revision 1.3 2004/05/12 09:41:55 anicoara
333
// Remove the README.RVM file
334
//
335
// Revision 1.2 2003/07/11 12:27:43 apopovic
336
// Bug fix for rare cases. Some classed loaded late may throw a 'NoClassDefError' when
337
// trying to retrieve the declared methods; The crosscut for such cases is now an empty listt
338
//
339
// Revision 1.1.1.1 2003/07/02 15:30:51 apopovic
340
// Imported from ETH Zurich
341
//
342
// Revision 1.4 2003/05/26 13:28:52 popovici
343
// Documentation Improvements
344
//
345
// Revision 1.3 2003/05/25 11:46:45 popovici
346
// Improved 'toString' presentation of aspects
347
//
348
// Revision 1.2 2003/05/05 17:57:45 popovici
349
// New cflow below pointcuter added; MethodCut fixed for usage in Cflow below (used not to be initialized once transported over the network)
350
//
351
// Revision 1.1 2003/05/05 13:58:11 popovici
352
// renaming from runes to prose
353
//
354
// Revision 1.18 2002/06/05 09:27:59 popovici
355
// thisJoinPoint() introduced in Abstract Crosscut and subclasses;
356
//
357
// Revision 1.17 2002/06/04 11:53:57 popovici
358
// Small refactorization: the DoNothingMatchAll UserDefinedMCSignature class src/ch/ethz/inf/runes/crosscut/MethodCut.java
359
// introduced to modell previous 'MethodCut' behavior. Class commented
360
//
361
// Revision 1.16 2002/06/03 13:11:02 popovici
362
// adviceSignature.methodObj.getParameterTypes() inlined
363
//
364
// Revision 1.15 2002/06/03 12:48:15 popovici
365
// renaming of the inner classes, objects, etc.
366
//
367
// Revision 1.14 2002/06/03 12:16:33 popovici
368
// heavy bug fixes of the Advice/Execution inner class structure
369
//
370
// Revision 1.13 2002/05/31 12:24:12 popovici
371
// methodAdvice simplified. Code moved to 5 inner classes
372
// of type 'McutAdvice'
373
//
374
// Revision 1.12 2002/05/31 09:00:11 popovici
375
// Bug fix in AdviceMehtod.matchSignature; reindentation
376
//
377
// Revision 1.11 2002/05/31 08:25:22 popovici
378
// Inner class 'Advice Method' creted.
379
//
380
// Revision 1.10 2002/05/30 15:37:15 popovici
381
// refactorization of 'doCreateCrosscut'. Usage of the
382
// newly introduced isGenericAssignable.
383
//
384
// Revision 1.9 2002/05/30 13:55:36 popovici
385
// doCreateCrosscut contained an (aparently) useless
386
// condition.
387
//
388
// Revision 1.8 2002/05/30 09:54:18 popovici
389
// 'isGeneric assignable' extracted from potentialCrosscutClasses
390
//
391
// Revision 1.7 2002/03/28 13:48:43 popovici
392
// Mozilla-ified
393
//
394
// Revision 1.6 2002/03/06 13:48:38 popovici
395
// joinPointAction now in 4 flavours, depending on the join point type
396
//
397
// Revision 1.5 2002/02/21 14:19:24 popovici
398
// Minor bug fix, rvm considers local variables too
399
//
400
// Revision 1.4 2002/02/21 12:39:20 popovici
401
// Crosscut efficiency issues:
402
// - joinPointAction dispatch based on static optimization
403
// (->doesEventSpecialization, 'setSpecializer' modified)
404
// (->calculation of 'adviceMethodOptimization', in Func.Crossc)
405
// - joinPointAction now uses JoinPoints (not Events)
406
// - JoinPointListeners (including crosscuts) now use joinPointReached(XXXJoinPoint) to avoid casting
407
// Crosscut architectural issues:
408
// - AbstractCrosscut now insertable.
409
// - AbstractCrosscuts owns referecnces to JVMAI
410
//
411
// Revision 1.3 2002/02/05 09:57:55 smarkwal
412
// JVMDI-specific code replaced by JVMAI. Prose-implementation classes and reflection package removed.
413
//
414
// Revision 1.1.1.1 2001/11/29 18:13:17 popovici
415
// Sources from runes
416
//
417
// Revision 1.1.2.18 2001/11/21 11:56:27 popovici
418
//
419
// -The sun.tools.agent and ch.ethz.inf.util.JVMDIUtil functionality
420
// replaced with the iks.jvmdi package. References to this old
421
// functionality replaced throughout the code.
422
// -Partial reimplementation of the ch.ethz.inf.iks.runes classes,
423
// part of their functionality moved to the ch.ethz.prose.reflect
424
// abstract classes. New classes and functionality added to the
425
// ch.ethz.prose.reflect package, partially to reflect the
426
// more stable features taken from the iks.runes packages, partially
427
// to reflect the structure of the VM (constant pool, etc). Functionality in
428
// ch.ethz.prose.crosscut and the junit classes adapted to use the
429
// new form of the ch.ethz.prose.reflect package
430
//
431
// Revision 1.1.2.17 2001/09/24 16:29:49 popovici
432
// demo errors removed
433
//
434
// Revision 1.1.2.16 2001/07/15 13:08:16 popovici
435
// Reimplemented using the 'isPotentialCrosscutClass' template method.
436
//
437
// Revision 1.1.2.15 2001/06/01 12:16:30 popovici
438
// Feature 'fix'. End-of-method location is now added to the join-point-
439
// requests only if it is different from the entry location.
440
//
441
// Revision 1.1.2.14 2001/05/21 12:31:43 popovici
442
// Bug fix: the last modification of the 'potentialCrosscutClasses' had
443
// induced a bug: the actual matching class, if not loaded, would not
444
// belong to the crosscut. Of course, the crosscut should take care
445
// at least to load the receiver class. This is now done.
446
//
447
// Revision 1.1.2.13 2001/05/17 12:18:09 popovici
448
// Important: Implementation and specification change. The advice method
449
// used to perform an *exact match* on the first argument. This condition
450
// is now relaxed. Thus, a 'Remote' in the as a first argument of this method
451
// selects all classes inheriting remote. This change improves dramatically
452
// insertion speed.
453
//
454
// Revision 1.1.2.12 2001/03/15 08:14:29 mrmuller
455
// minor change in logging
456
//
457
// Revision 1.1.2.11 2001/02/21 13:31:43 popovici
458
// Specialization of the 'toString' method to show method advice too.
459
//
460
// Revision 1.1.2.10 2001/02/13 18:42:11 popovici
461
// Bug fix: for advice signatures like '(ANY)' the code used
462
// to match everything
463
//
464
// Revision 1.1.2.9 2001/02/13 15:13:26 mrmuller
465
// Native methods excluded from functional crosscut
466
//
467
// Revision 1.1.2.8 2001/02/07 11:51:39 popovici
468
// Initial Revision
469
//
470
// Revision 1.1.2.7 2001/01/18 14:22:20 popovici
471
// Implementation of 'localActionImpl' changed in order to avoid
472
// costly Vector.addAll operations. The special-case 'this' variable is
473
// now taken care of outside the main loop
474
//
475
// Revision 1.1.2.6 2001/01/18 13:07:01 groos
476
// - doCreateRequest() modified to take all *declared* methods of
477
// the given class instead of all public methods (incl. inherited
478
// methods)
479
//
480
// Revision 1.1.2.5 2000/12/01 09:24:32 popovici
481
// Bug fixes:
482
// 1. Crosscut does not cut accross abstract methods
483
// 2. Advice method now callable even if in inner class
484
// 3. Documentation added
485
//
486
// Revision 1.1.2.4 2000/11/15 15:15:32 popovici
487
// joinPointAction throws now IllegalAccessException too
488
//
489
// Revision 1.1.2.3 2000/10/30 17:28:57 groos
490
// documentation updates
491
//
492
// Revision 1.1.2.2 2000/10/25 09:09:07 popovici
493
// Bug fixed in 'localActionImpl': 'REST' did not match empty lists
494
// of parameters (exception triggered before check). Fixed.
495
//
496
// Revision 1.1.2.1 2000/10/23 18:36:37 popovici
497
// Initial Revision
498
//
499
Popular Tags