KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > transform > inlining > weaver > InstanceLevelAspectVisitor


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.transform.inlining.weaver;
5
6 import java.util.Set JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.Collection JavaDoc;
9
10 import com.tc.asm.*;
11
12 import com.tc.aspectwerkz.DeploymentModel;
13 import com.tc.aspectwerkz.expression.PointcutType;
14 import com.tc.aspectwerkz.expression.ExpressionInfo;
15 import com.tc.aspectwerkz.expression.ExpressionContext;
16 import com.tc.aspectwerkz.reflect.ClassInfo;
17 import com.tc.aspectwerkz.definition.AdviceDefinition;
18 import com.tc.aspectwerkz.definition.DeploymentScope;
19 import com.tc.aspectwerkz.definition.SystemDefinition;
20 import com.tc.aspectwerkz.perx.PerObjectAspect;
21 import com.tc.aspectwerkz.transform.InstrumentationContext;
22 import com.tc.aspectwerkz.transform.TransformationConstants;
23
24 /**
25  * Adds an instance level aspect management to the target class.
26  *
27  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
28  * @author <a HREF='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
29  */

30 public class InstanceLevelAspectVisitor extends ClassAdapter implements TransformationConstants {
31
32   private final InstrumentationContext m_ctx;
33   private final ClassInfo m_classInfo;
34   private boolean m_isAdvised = false;
35
36   /**
37    * Creates a new add interface class adapter.
38    *
39    * @param cv
40    * @param classInfo
41    * @param ctx
42    */

43   public InstanceLevelAspectVisitor(final ClassVisitor cv,
44                                     final ClassInfo classInfo,
45                                     final InstrumentationContext ctx) {
46     super(cv);
47     m_classInfo = classInfo;
48     m_ctx = (InstrumentationContext) ctx;
49   }
50
51   /**
52    * Visits the class.
53    *
54    * @param access
55    * @param name
56    * @param signature
57    * @param superName
58    * @param interfaces
59    */

60   public void visit(final int version,
61                     final int access,
62                     final String JavaDoc name,
63                     final String JavaDoc signature,
64                     final String JavaDoc superName,
65                     final String JavaDoc[] interfaces) {
66
67     if (classFilter(m_classInfo, m_ctx.getDefinitions())) {
68       super.visit(version, access, name, signature, superName, interfaces);
69       return;
70     }
71
72     for (int i = 0; i < interfaces.length; i++) {
73       String JavaDoc anInterface = interfaces[i];
74       if (anInterface.equals(HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME)) {
75         super.visit(version, access, name, signature, superName, interfaces);
76         return;
77       }
78     }
79     String JavaDoc[] newInterfaceArray = new String JavaDoc[interfaces.length + 1];
80     System.arraycopy(interfaces, 0, newInterfaceArray, 0, interfaces.length);
81     newInterfaceArray[interfaces.length] = HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME;
82
83     // add the interface
84
super.visit(version, access, name, signature, superName, newInterfaceArray);
85
86     // add the field with the aspect instance map
87
addAspectMapField();
88
89     // add the getAspect(..) method
90
addGetAspectMethod(name);
91
92     // add the hasAspect(...) method
93
addHasAspectMethod(name);
94
95     addBindAspectMethod(name);
96   }
97
98   /**
99    * Appends mixin instantiation to the clinit method and/or init method.
100    *
101    * @param access
102    * @param name
103    * @param desc
104    * @param signature
105    * @param exceptions
106    * @return
107    */

108   public MethodVisitor visitMethod(final int access,
109                                    final String JavaDoc name,
110                                    final String JavaDoc desc,
111                                    final String JavaDoc signature,
112                                    final String JavaDoc[] exceptions) {
113     if (m_isAdvised) {
114       if (name.equals(INIT_METHOD_NAME)) {
115         MethodVisitor mv = new AppendToInitMethodCodeAdapter(
116                 cv.visitMethod(access, name, desc, signature, exceptions),
117                 name
118         );
119         mv.visitMaxs(0, 0);
120         return mv;
121       }
122     }
123     return cv.visitMethod(access, name, desc, signature, exceptions);
124   }
125
126   /**
127    * Adds the aspect map field to the target class.
128    */

129   private void addAspectMapField() {
130     super.visitField(
131             ACC_PRIVATE + ACC_SYNTHETIC + ACC_TRANSIENT,
132             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
133             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE,
134             null, null
135     );
136   }
137
138   /**
139    * Adds the getAspect(..) method to the target class.
140    *
141    * @param name the class name of the target class
142    */

143   private void addGetAspectMethod(final String JavaDoc name) {
144     MethodVisitor cv = super.visitMethod(
145             ACC_PUBLIC + ACC_SYNTHETIC,
146             INSTANCE_LEVEL_GETASPECT_METHOD_NAME,
147             INSTANCE_LEVEL_GETASPECT_METHOD_SIGNATURE,
148             null, null
149     );
150
151     cv.visitVarInsn(ALOAD, 0);
152     cv.visitFieldInsn(
153             GETFIELD,
154             name,
155             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
156             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
157     );
158     //--
159
cv.visitInsn(DUP);
160     Label ifMapNonNull = new Label();
161     cv.visitJumpInsn(IFNONNULL, ifMapNonNull);
162     cv.visitInsn(ACONST_NULL);
163     cv.visitInsn(ARETURN);
164     cv.visitLabel(ifMapNonNull);
165
166 // // if == null, field = new HashMap()
167
// Label ifFieldNullNotLabel = new Label();
168
// cv.visitJumpInsn(IFNONNULL, ifFieldNullNotLabel);
169
// cv.visitVarInsn(ALOAD, 0);
170
// cv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
171
// cv.visitInsn(DUP);
172
// cv.visitMethodInsn(
173
// INVOKESPECIAL,
174
// HASH_MAP_CLASS_NAME,
175
// INIT_METHOD_NAME,
176
// NO_PARAM_RETURN_VOID_SIGNATURE
177
// );
178
// cv.visitFieldInsn(
179
// PUTFIELD,
180
// name,
181
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
182
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
183
// );
184
// cv.visitLabel(ifFieldNullNotLabel);
185
//
186
// cv.visitVarInsn(ALOAD, 0);
187
// cv.visitFieldInsn(
188
// GETFIELD,
189
// name,
190
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
191
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
192
// );
193
//
194
// cv.visitVarInsn(ALOAD, 2);//qName
195
// cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, GET_METHOD_NAME, GET_METHOD_SIGNATURE);
196
// cv.visitVarInsn(ASTORE, 4);
197
// cv.visitVarInsn(ALOAD, 4);
198
// Label ifNullNotLabel = new Label();
199
// cv.visitJumpInsn(IFNONNULL, ifNullNotLabel);
200
// cv.visitVarInsn(ALOAD, 2);//qName
201
// cv.visitVarInsn(ALOAD, 3);//containerClassName
202
// cv.visitVarInsn(ALOAD, 0);//this (perInstance)
203
// cv.visitMethodInsn(
204
// INVOKESTATIC,
205
// ASPECTS_CLASS_NAME,
206
// ASPECT_OF_METHOD_NAME,
207
// ASPECT_OF_PER_INSTANCE_METHOD_SIGNATURE
208
// );
209
// cv.visitVarInsn(ASTORE, 4);
210
//cv.visitVarInsn(ALOAD, 0);
211
//--
212
cv.visitVarInsn(ALOAD, 1);
213     cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, GET_METHOD_NAME, GET_METHOD_SIGNATURE);
214     //--
215
// cv.visitFieldInsn(
216
// GETFIELD,
217
// name,
218
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
219
// INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
220
// );
221
cv.visitInsn(ARETURN);
222 // cv.visitVarInsn(ALOAD, 2);
223
// cv.visitVarInsn(ALOAD, 4);
224
// cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, PUT_METHOD_NAME, PUT_METHOD_SIGNATURE);
225
// cv.visitInsn(POP);
226
// cv.visitLabel(ifNullNotLabel);
227
// cv.visitVarInsn(ALOAD, 4);
228
// cv.visitInsn(ARETURN);
229
cv.visitMaxs(0, 0);
230
231     m_ctx.markAsAdvised();
232     m_isAdvised = true;
233   }
234
235   private void addHasAspectMethod(String JavaDoc mapFieldName) {
236     MethodVisitor cv = super.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC,
237             INSTANCE_LEVEL_HASASPECT_METHOD_NAME,
238             INSTANCE_LEVEL_HASASPECT_METHOD_SIGNATURE,
239             null,
240             null
241     );
242
243     cv.visitVarInsn(ALOAD, 0);
244     cv.visitFieldInsn(GETFIELD,
245             mapFieldName,
246             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
247             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
248     );
249     cv.visitInsn(DUP);
250     Label ifMapNonNull = new Label();
251     cv.visitJumpInsn(IFNONNULL, ifMapNonNull);
252     cv.visitInsn(ICONST_0);
253     cv.visitInsn(IRETURN);
254     cv.visitLabel(ifMapNonNull);
255     cv.visitVarInsn(ALOAD, 1);
256     cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, "containsKey", "(Ljava/lang/Object;)Z");
257     //cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, GET_METHOD_NAME, GET_METHOD_SIGNATURE);
258
//
259
// Label ifNullLabel = new Label();
260
// cv.visitJumpInsn(IFNULL, ifNullLabel);
261
// cv.visitInsn(ICONST_1);
262
// cv.visitInsn(IRETURN);
263
// cv.visitLabel(ifNullLabel);
264
// cv.visitInsn(ICONST_0);
265
cv.visitInsn(IRETURN);
266     cv.visitMaxs(0, 0);
267
268     m_ctx.markAsAdvised();
269     m_isAdvised = true;
270   }
271
272   private void addBindAspectMethod(final String JavaDoc name) {
273     MethodVisitor cv = super.visitMethod(
274             ACC_PUBLIC + ACC_SYNTHETIC,
275             INSTANCE_LEVEL_BINDASPECT_METHOD_NAME,
276             INSTANCE_LEVEL_BINDASPECT_METHOD_SIGNATURE,
277             null, null
278     );
279
280     cv.visitVarInsn(ALOAD, 0);
281     cv.visitFieldInsn(
282             GETFIELD,
283             name,
284             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
285             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
286     );
287     // if == null, field = new HashMap()
288
Label ifFieldNullNotLabel = new Label();
289     cv.visitJumpInsn(IFNONNULL, ifFieldNullNotLabel);
290     cv.visitVarInsn(ALOAD, 0);
291     cv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
292     cv.visitInsn(DUP);
293     cv.visitMethodInsn(
294             INVOKESPECIAL,
295             HASH_MAP_CLASS_NAME,
296             INIT_METHOD_NAME,
297             NO_PARAM_RETURN_VOID_SIGNATURE
298     );
299     cv.visitFieldInsn(
300             PUTFIELD,
301             name,
302             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
303             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
304     );
305     cv.visitLabel(ifFieldNullNotLabel);
306
307     cv.visitVarInsn(ALOAD, 0);
308     cv.visitFieldInsn(
309             GETFIELD,
310             name,
311             INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
312             INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
313     );
314     cv.visitVarInsn(ALOAD, 1);
315     cv.visitVarInsn(ALOAD, 2);
316     cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, PUT_METHOD_NAME, PUT_METHOD_SIGNATURE);
317     cv.visitVarInsn(ALOAD, 2);
318     cv.visitInsn(ARETURN);
319   }
320
321   /**
322    * Filters the classes to be transformed.
323    *
324    * @param classInfo the class to filter
325    * @param definitions a set with the definitions
326    * @return boolean true if the method should be filtered away
327    */

328   public static boolean classFilter(final ClassInfo classInfo, final Set JavaDoc definitions) {
329     if (classInfo.isInterface()) {
330       return true;
331     }
332
333     ExpressionContext ctx = new ExpressionContext(PointcutType.WITHIN, null, classInfo);
334
335     for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
336       SystemDefinition systemDef = (SystemDefinition) it.next();
337       String JavaDoc className = classInfo.getName().replace('/', '.');
338       if (systemDef.inExcludePackage(className)) {
339         return true;
340       }
341       if (!systemDef.inIncludePackage(className)) {
342         return true;
343       }
344
345       Collection JavaDoc adviceDefs = systemDef.getAdviceDefinitions();
346       for (Iterator JavaDoc defs = adviceDefs.iterator(); defs.hasNext();) {
347         AdviceDefinition adviceDef = (AdviceDefinition) defs.next();
348         ExpressionInfo expressionInfo = adviceDef.getExpressionInfo();
349         if (expressionInfo == null) {
350           continue;
351         }
352         DeploymentModel deploymentModel = adviceDef.getDeploymentModel();
353
354         // match on perinstance deployed aspects
355
if (DeploymentModel.PER_INSTANCE.equals(deploymentModel)) {
356           if (expressionInfo.getAdvisedClassFilterExpression().match(ctx)) {
357             return false;
358           }
359         }
360
361         // match on perthis/pertarget perX X pointcuts
362
if (adviceDef.getAspectClassName().equals(PerObjectAspect.PEROBJECT_ASPECT_NAME)) {
363           ExpressionInfo perXExpressionInfo = adviceDef.getExpressionInfo();
364           if (perXExpressionInfo.getAdvisedClassFilterExpression().match(ctx)) {
365             return false;
366           }
367         }
368       }
369
370       // match on deployment scopes, e.g. potential perinstance deployment aspects
371
Collection JavaDoc deploymentScopes = systemDef.getDeploymentScopes();
372       for (Iterator JavaDoc scopes = deploymentScopes.iterator(); scopes.hasNext();) {
373         DeploymentScope deploymentScope = (DeploymentScope) scopes.next();
374         ExpressionInfo expression = new ExpressionInfo(
375                 deploymentScope.getExpression(),
376                 systemDef.getUuid()
377         );
378         if (expression.getAdvisedClassFilterExpression().match(ctx)) {
379           return false;
380         }
381       }
382     }
383
384     return true;
385   }
386
387   /**
388    * Adds initialization of aspect map field to end of the init method.
389    *
390    * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
391    */

392   private class AppendToInitMethodCodeAdapter extends AfterObjectInitializationCodeAdapter {
393
394     private boolean m_done = false;
395
396     public AppendToInitMethodCodeAdapter(final MethodVisitor ca, String JavaDoc callerMemberName) {
397       super(ca, callerMemberName);
398     }
399
400     /**
401      * Inserts the init of the aspect field right after the call to super(..) of this(..).
402      *
403      * @param opcode
404      * @param owner
405      * @param name
406      * @param desc
407      */

408     public void visitMethodInsn(int opcode,
409                                 String JavaDoc owner,
410                                 String JavaDoc name,
411                                 String JavaDoc desc) {
412       super.visitMethodInsn(opcode, owner, name, desc);
413       if (opcode == INVOKESPECIAL && m_isObjectInitialized && !m_done) {
414         m_done = true;
415
416         // initialize aspect map field
417
mv.visitVarInsn(ALOAD, 0);
418         mv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
419         mv.visitInsn(DUP);
420         mv.visitMethodInsn(
421                 INVOKESPECIAL,
422                 HASH_MAP_CLASS_NAME,
423                 INIT_METHOD_NAME,
424                 NO_PARAM_RETURN_VOID_SIGNATURE
425         );
426         mv.visitFieldInsn(
427                 PUTFIELD,
428                 m_classInfo.getName().replace('.', '/'),
429                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
430                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
431         );
432       }
433     }
434   }
435 }
436
Popular Tags