KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > transform > inlining > weaver > HandlerVisitor


1 /**************************************************************************************
2  * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.transform.inlining.weaver;
9
10 import org.objectweb.asm.ClassAdapter;
11 import org.objectweb.asm.ClassVisitor;
12 import org.objectweb.asm.CodeVisitor;
13 import org.objectweb.asm.Attribute;
14 import org.objectweb.asm.CodeAdapter;
15 import org.objectweb.asm.Label;
16 import org.objectweb.asm.Type;
17 import org.codehaus.aspectwerkz.definition.SystemDefinition;
18 import org.codehaus.aspectwerkz.expression.ExpressionContext;
19 import org.codehaus.aspectwerkz.expression.PointcutType;
20 import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
21 import org.codehaus.aspectwerkz.reflect.ClassInfo;
22 import org.codehaus.aspectwerkz.reflect.MemberInfo;
23 import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
24 import org.codehaus.aspectwerkz.transform.Context;
25 import org.codehaus.aspectwerkz.transform.TransformationUtil;
26 import org.codehaus.aspectwerkz.transform.TransformationConstants;
27 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
28 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
29 import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
30
31 import java.util.Iterator JavaDoc;
32 import java.util.Set JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.lang.reflect.Modifier JavaDoc;
38
39 /**
40  * Advises catch clauses by inserting a call to the join point as the first thing in the catch block.
41  *
42  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
43  */

44 public class HandlerVisitor extends ClassAdapter implements TransformationConstants {
45
46     /**
47      * A visitor that looks for all catch clause and keep track of them
48      * providing that they match
49      *
50      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
51      */

52     public static class LookaheadCatchLabelsClassAdapter extends ClassAdapter {
53         /**
54          * list of CatchLabelStruct that matches
55          */

56         List JavaDoc m_catchLabels = new ArrayList JavaDoc();
57
58         /**
59          * map of Integer(index in whole class)-->asm.Label for all the visited labels
60          */

61         private final Map JavaDoc m_labelIndexes = new HashMap JavaDoc();
62
63         /**
64          * current label index in whole class, from 0 to N
65          */

66         private int m_labelIndex = -1;
67
68         private final ContextImpl m_ctx;
69         private final ClassLoader JavaDoc m_loader;
70         private final ClassInfo m_callerClassInfo;
71
72         /**
73          * Visit the class
74          *
75          * @param cv
76          * @param loader
77          * @param callerClassInfo
78          * @param ctx
79          * @param catchLabels
80          */

81         public LookaheadCatchLabelsClassAdapter(ClassVisitor cv, ClassLoader JavaDoc loader, ClassInfo callerClassInfo,
82                                                 Context ctx, List JavaDoc catchLabels) {
83             super(cv);
84             m_catchLabels = catchLabels;
85             m_loader = loader;
86             m_callerClassInfo = callerClassInfo;
87             m_ctx = (ContextImpl) ctx;
88         }
89
90         /**
91          * Visit method bodies
92          *
93          * @param access
94          * @param callerMethodName
95          * @param callerMethodDesc
96          * @param exceptions
97          * @param attrs
98          * @return
99          */

100         public CodeVisitor visitMethod(final int access,
101                                        final String JavaDoc callerMethodName,
102                                        final String JavaDoc callerMethodDesc,
103                                        final String JavaDoc[] exceptions,
104                                        final Attribute attrs) {
105             if (callerMethodName.startsWith(WRAPPER_METHOD_PREFIX)) {
106                 return super.visitMethod(access, callerMethodName, callerMethodDesc, exceptions, attrs);
107             }
108
109             CodeVisitor mv = cv.visitMethod(access, callerMethodName, callerMethodDesc, exceptions, attrs);
110             if (mv == null) {
111                 return mv;
112             }
113
114             final MemberInfo callerMemberInfo;
115             if (CLINIT_METHOD_NAME.equals(callerMethodName)) {
116                 callerMemberInfo = m_callerClassInfo.staticInitializer();
117             } else if (INIT_METHOD_NAME.equals(callerMethodName)) {
118                 int hash = AsmHelper.calculateConstructorHash(callerMethodDesc);
119                 callerMemberInfo = m_callerClassInfo.getConstructor(hash);
120             } else {
121                 int hash = AsmHelper.calculateMethodHash(callerMethodName, callerMethodDesc);
122                 callerMemberInfo = m_callerClassInfo.getMethod(hash);
123             }
124             if (callerMemberInfo == null) {
125                 System.err.println(
126                         "AW::WARNING " +
127                         "metadata structure could not be build for method ["
128                         + m_callerClassInfo.getName().replace('/', '.')
129                         + '.' + callerMethodName + ':' + callerMethodDesc + ']'
130                 );
131                 return mv;
132             }
133
134             /**
135              * Visit the method, and keep track of all labels so that when visittryCatch is reached
136              * we can remember the index
137              *
138              * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
139              */

140             return new CodeAdapter(mv) {
141                 public void visitLabel(Label label) {
142                     m_labelIndexes.put(label, new Integer JavaDoc(++m_labelIndex));
143                     super.visitLabel(label);
144                 }
145
146                 public void visitTryCatchBlock(Label startLabel, Label endLabel, Label handlerLabel,
147                                                String JavaDoc exceptionTypeName) {
148                     if (exceptionTypeName == null) {
149                         // finally block
150
super.visitTryCatchBlock(startLabel, endLabel, handlerLabel, exceptionTypeName);
151                         return;
152                     }
153                     final ClassInfo exceptionClassInfo = AsmClassInfo.getClassInfo(exceptionTypeName, m_loader);
154                     final ExpressionContext ctx = new ExpressionContext(
155                             PointcutType.HANDLER, exceptionClassInfo, callerMemberInfo
156                     );
157                     if (!handlerFilter(m_ctx.getDefinitions(), ctx)) {
158                         // remember its index and the exception exceptionClassInfo
159
Integer JavaDoc index = (Integer JavaDoc) m_labelIndexes.get(handlerLabel);
160                         if (index != null) {
161                             m_catchLabels.add(
162                                     new CatchLabelStruct(
163                                             index.intValue(),
164                                             exceptionClassInfo,
165                                             m_callerClassInfo,
166                                             callerMemberInfo
167                                     )
168                             );
169                         }
170                     }
171                     super.visitTryCatchBlock(startLabel, endLabel, handlerLabel, exceptionTypeName);
172                 }
173             };
174         }
175     }
176
177     //---- non lookahead visitor
178

179     private final ContextImpl m_ctx;
180
181     /**
182      * List of matching catch clause
183      */

184     private final List JavaDoc m_catchLabels;
185
186     /**
187      * catch clause index in whole class
188      */

189     private int m_labelIndex = -1;
190
191     private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER;
192
193
194     /**
195      * Creates a new instance.
196      *
197      * @param cv
198      * @param ctx
199      */

200     public HandlerVisitor(final ClassVisitor cv,
201                           final Context ctx,
202                           final List JavaDoc catchLabels) {
203         super(cv);
204         m_ctx = (ContextImpl) ctx;
205         m_catchLabels = catchLabels;
206     }
207
208     /**
209      * Visits the methods bodies to weave in JP calls at catch clauses
210      *
211      * @param access
212      * @param name
213      * @param desc
214      * @param exceptions
215      * @param attrs
216      * @return
217      */

218     public CodeVisitor visitMethod(final int access,
219                                    final String JavaDoc name,
220                                    final String JavaDoc desc,
221                                    final String JavaDoc[] exceptions,
222                                    final Attribute attrs) {
223         if (name.startsWith(WRAPPER_METHOD_PREFIX)) {
224             return super.visitMethod(access, name, desc, exceptions, attrs);
225         }
226
227         CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions, attrs);
228         return mv == null ? null : new CatchClauseCodeAdapter(mv);
229     }
230
231     /**
232      * Advises catch clauses by inserting a call to the join point as the first thing in the catch block.
233      *
234      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
235      */

236     public class CatchClauseCodeAdapter extends CodeAdapter {
237
238         /**
239          * Creates a new instance.
240          *
241          * @param ca
242          */

243         public CatchClauseCodeAdapter(final CodeVisitor ca) {
244             super(ca);
245         }
246
247         public void visitLabel(Label label) {
248             m_lastLabelForLineNumber = label;
249             super.visitLabel(label);
250
251             // check if it is a catch label
252
int index = ++m_labelIndex;
253             CatchLabelStruct catchLabel = null;
254             for (Iterator JavaDoc iterator = m_catchLabels.iterator(); iterator.hasNext();) {
255                 CatchLabelStruct aCatchLabel = (CatchLabelStruct) iterator.next();
256                 if (aCatchLabel.labelIndexInWholeClass == index) {
257                     catchLabel = aCatchLabel;
258                     break;
259                 }
260             }
261             if (catchLabel == null) {
262                 return;
263             }
264             // matched
265
m_ctx.markAsAdvised();
266             final String JavaDoc callerTypeName = catchLabel.caller.getName().replace('.', '/');
267             final String JavaDoc exceptionTypeDesc = catchLabel.exception.getSignature();
268             final String JavaDoc exceptionTypeName = Type.getType(exceptionTypeDesc).getInternalName();
269             final int joinPointHash = AsmHelper.calculateClassHash(exceptionTypeDesc);
270             final String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
271                     callerTypeName,
272                     catchLabel.callerMember.getName(),
273                     catchLabel.callerMember.getSignature(),
274                     exceptionTypeName,
275                     JoinPointType.HANDLER_INT,
276                     joinPointHash
277             );
278
279             // add the call to the join point
280
// exception instance is on the stack
281
// dup it for ARG0
282
cv.visitInsn(DUP);
283
284             // load caller instance if any
285
if (Modifier.isStatic(catchLabel.callerMember.getModifiers())) {
286                 cv.visitInsn(ACONST_NULL);
287             } else {
288                 cv.visitVarInsn(ALOAD, 0);
289             }
290             //TODO for now we pass the exception as both CALLEE and ARG0 - may be callee must be NULL
291
//? check in AJ RTTI
292
cv.visitMethodInsn(
293                     INVOKESTATIC, joinPointClassName, INVOKE_METHOD_NAME,
294                     TransformationUtil.getInvokeSignatureForHandlerJoinPoints(callerTypeName, exceptionTypeName)
295             );
296
297             // emit the joinpoint
298
m_ctx.addEmittedJoinPoint(
299                     new EmittedJoinPoint(
300                             JoinPointType.HANDLER_INT,
301                             callerTypeName,
302                             catchLabel.callerMember.getName(),
303                             catchLabel.callerMember.getSignature(),
304                             catchLabel.callerMember.getModifiers(),
305                             exceptionTypeName,
306                             "",
307                             exceptionTypeDesc,
308                             0, // a bit meaningless but must not be static
309
joinPointHash,
310                             joinPointClassName,
311                             m_lastLabelForLineNumber
312                     )
313             );
314         }
315     }
316
317     /**
318      * Filters out the catch clauses that are not eligible for transformation.
319      *
320      * @param definitions
321      * @param ctx
322      * @return boolean true if the catch clause should be filtered out
323      */

324     static boolean handlerFilter(final Set JavaDoc definitions, final ExpressionContext ctx) {
325         for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
326             if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
327                 return false;
328             } else {
329                 continue;
330             }
331         }
332         return true;
333     }
334
335     /**
336      * A struct to represent a catch clause.
337      * The index is class wide, and the exception class info is kept.
338      *
339      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
340      */

341     private static class CatchLabelStruct {
342         int labelIndexInWholeClass = -1;
343         ClassInfo exception = null;
344         ClassInfo caller = null;
345         MemberInfo callerMember = null;
346
347         private CatchLabelStruct(int indexInClass, ClassInfo exception, ClassInfo caller, MemberInfo callerMember) {
348             labelIndexInWholeClass = indexInClass;
349             this.exception = exception;
350             this.caller = caller;
351             this.callerMember = callerMember;
352         }
353     }
354 }
Popular Tags