KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.Set JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.HashMap JavaDoc;
14
15 import org.objectweb.asm.*;
16 import org.codehaus.aspectwerkz.transform.Context;
17 import org.codehaus.aspectwerkz.transform.TransformationConstants;
18 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
19 import org.codehaus.aspectwerkz.reflect.ClassInfo;
20 import org.codehaus.aspectwerkz.expression.ExpressionContext;
21 import org.codehaus.aspectwerkz.expression.PointcutType;
22 import org.codehaus.aspectwerkz.expression.ExpressionInfo;
23 import org.codehaus.aspectwerkz.definition.SystemDefinition;
24 import org.codehaus.aspectwerkz.definition.AdviceDefinition;
25 import org.codehaus.aspectwerkz.definition.DeploymentScope;
26 import org.codehaus.aspectwerkz.DeploymentModel;
27
28 /**
29  * Adds an instance level aspect management to the target class.
30  *
31  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
32  */

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

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

63     public void visit(final int version,
64                       final int access,
65                       final String JavaDoc name,
66                       final String JavaDoc superName,
67                       final String JavaDoc[] interfaces,
68                       final String JavaDoc sourceFile) {
69
70         if (classFilter(m_classInfo, m_ctx.getDefinitions())) {
71             super.visit(version, access, name, superName, interfaces, sourceFile);
72             return;
73         }
74
75         for (int i = 0; i < interfaces.length; i++) {
76             String JavaDoc anInterface = interfaces[i];
77             if (anInterface.equals(HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME)) {
78                 super.visit(version, access, name, superName, interfaces, sourceFile);
79                 return;
80             }
81         }
82         String JavaDoc[] newInterfaceArray = new String JavaDoc[interfaces.length + 1];
83         for (int i = 0; i < interfaces.length; i++) {
84             newInterfaceArray[i] = interfaces[i];
85         }
86         newInterfaceArray[interfaces.length] = HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME;
87
88         // add the interface
89
super.visit(version, access, name, superName, newInterfaceArray, sourceFile);
90
91         // add the field with the aspect instance map
92
addAspectMapField();
93
94         // add the getAspect(..) method
95
addGetAspectMethod(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 exceptions
105      * @param attrs
106      * @return
107      */

108     public CodeVisitor visitMethod(final int access,
109                                    final String JavaDoc name,
110                                    final String JavaDoc desc,
111                                    final String JavaDoc[] exceptions,
112                                    final Attribute attrs) {
113         if (m_isAdvised) {
114             if (name.equals(INIT_METHOD_NAME)) {
115                 CodeVisitor mv = new AppendToInitMethodCodeAdapter(
116                         cv.visitMethod(access, name, desc, exceptions, attrs),
117                         name
118                 );
119                 mv.visitMaxs(0, 0);
120                 return mv;
121             }
122         }
123         return cv.visitMethod(access, name, desc, exceptions, attrs);
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         CodeVisitor cv = super.visitMethod(
145                 ACC_PUBLIC + ACC_SYNTHETIC,
146                 GET_INSTANCE_LEVEL_ASPECT_METHOD_NAME,
147                 GET_INSTANCE_LEVEL_ASPECT_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         // if == null, field = new HashMap()
160
Label ifFieldNullNotLabel = new Label();
161         cv.visitJumpInsn(IFNONNULL, ifFieldNullNotLabel);
162         cv.visitVarInsn(ALOAD, 0);
163         cv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
164         cv.visitInsn(DUP);
165         cv.visitMethodInsn(
166                 INVOKESPECIAL,
167                 HASH_MAP_CLASS_NAME,
168                 INIT_METHOD_NAME,
169                 NO_PARAM_RETURN_VOID_SIGNATURE
170         );
171         cv.visitFieldInsn(
172                 PUTFIELD,
173                 m_classInfo.getName().replace('.', '/'),
174                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
175                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
176         );
177         cv.visitLabel(ifFieldNullNotLabel);
178
179         cv.visitVarInsn(ALOAD, 0);
180         cv.visitFieldInsn(
181                 GETFIELD,
182                 name,
183                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
184                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
185         );
186
187         cv.visitVarInsn(ALOAD, 2);//qName
188
cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, GET_METHOD_NAME, GET_METHOD_SIGNATURE);
189         cv.visitVarInsn(ASTORE, 4);
190         cv.visitVarInsn(ALOAD, 4);
191         Label ifNullNotLabel = new Label();
192         cv.visitJumpInsn(IFNONNULL, ifNullNotLabel);
193         cv.visitVarInsn(ALOAD, 2);//qName
194
cv.visitVarInsn(ALOAD, 3);//containerClassName
195
cv.visitVarInsn(ALOAD, 0);//this (perInstance)
196
cv.visitMethodInsn(
197                 INVOKESTATIC,
198                 ASPECTS_CLASS_NAME,
199                 ASPECT_OF_METHOD_NAME,
200                 ASPECT_OF_PER_INSTANCE_METHOD_SIGNATURE
201         );
202         cv.visitVarInsn(ASTORE, 4);
203         cv.visitVarInsn(ALOAD, 0);
204         cv.visitFieldInsn(
205                 GETFIELD,
206                 name,
207                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
208                 INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
209         );
210         cv.visitVarInsn(ALOAD, 2);
211         cv.visitVarInsn(ALOAD, 4);
212         cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, PUT_METHOD_NAME, PUT_METHOD_SIGNATURE);
213         cv.visitInsn(POP);
214         cv.visitLabel(ifNullNotLabel);
215         cv.visitVarInsn(ALOAD, 4);
216         cv.visitInsn(ARETURN);
217         cv.visitMaxs(0, 0);
218
219         m_ctx.markAsAdvised();
220         m_isAdvised = true;
221     }
222
223     /**
224      * Filters the classes to be transformed.
225      *
226      * @param classInfo the class to filter
227      * @param definitions a set with the definitions
228      * @return boolean true if the method should be filtered away
229      */

230     public static boolean classFilter(final ClassInfo classInfo, final Set JavaDoc definitions) {
231         if (classInfo.isInterface()) {
232             return true;
233         }
234
235         ExpressionContext ctx = new ExpressionContext(PointcutType.WITHIN, null, classInfo);
236
237         for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
238             SystemDefinition systemDef = (SystemDefinition) it.next();
239             String JavaDoc className = classInfo.getName().replace('/', '.');
240             if (systemDef.inExcludePackage(className)) {
241                 return true;
242             }
243             if (!systemDef.inIncludePackage(className)) {
244                 return true;
245             }
246
247             // match on perinstance deployed aspects
248
Collection JavaDoc adviceDefs = systemDef.getAdviceDefinitions();
249             for (Iterator JavaDoc defs = adviceDefs.iterator(); defs.hasNext();) {
250                 AdviceDefinition adviceDef = (AdviceDefinition) defs.next();
251                 ExpressionInfo expressionInfo = adviceDef.getExpressionInfo();
252                 if (expressionInfo == null) {
253                     continue;
254                 }
255                 if (adviceDef.getAspectDefinition().getDeploymentModel().equals(DeploymentModel.PER_INSTANCE)
256                     && expressionInfo.getAdvisedClassFilterExpression().match(ctx)) {
257                     return false;
258                 }
259             }
260
261             // match on deployment scopes, e.g. potential perinstance deployment aspects
262
Collection JavaDoc deploymentScopes = systemDef.getDeploymentScopes();
263             for (Iterator JavaDoc scopes = deploymentScopes.iterator(); scopes.hasNext();) {
264                 DeploymentScope deploymentScope = (DeploymentScope) scopes.next();
265                 ExpressionInfo expression = new ExpressionInfo(
266                         deploymentScope.getExpression(),
267                         systemDef.getUuid()
268                 );
269                 if (expression.getAdvisedClassFilterExpression().match(ctx)) {
270                     return false;
271                 }
272             }
273         }
274
275         return true;
276     }
277
278     /**
279      * Adds initialization of aspect map field to end of the init method.
280      *
281      * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
282      */

283     private class AppendToInitMethodCodeAdapter extends AfterObjectInitializationCodeAdapter {
284
285         private boolean m_done = false;
286
287         public AppendToInitMethodCodeAdapter(final CodeVisitor ca, String JavaDoc callerMemberName) {
288             super(ca, callerMemberName);
289         }
290
291         /**
292          * Inserts the init of the aspect field right after the call to super(..) of this(..).
293          *
294          * @param opcode
295          * @param owner
296          * @param name
297          * @param desc
298          */

299         public void visitMethodInsn(int opcode,
300                                     String JavaDoc owner,
301                                     String JavaDoc name,
302                                     String JavaDoc desc) {
303             super.visitMethodInsn(opcode, owner, name, desc);
304             if (opcode == INVOKESPECIAL && m_isObjectInitialized && !m_done) {
305                 m_done = true;
306
307                 // initialize aspect map field
308
cv.visitVarInsn(ALOAD, 0);
309                 cv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
310                 cv.visitInsn(DUP);
311                 cv.visitMethodInsn(
312                         INVOKESPECIAL,
313                         HASH_MAP_CLASS_NAME,
314                         INIT_METHOD_NAME,
315                         NO_PARAM_RETURN_VOID_SIGNATURE
316                 );
317                 cv.visitFieldInsn(
318                         PUTFIELD,
319                         m_classInfo.getName().replace('.', '/'),
320                         INSTANCE_LEVEL_ASPECT_MAP_FIELD_NAME,
321                         INSTANCE_LEVEL_ASPECT_MAP_FIELD_SIGNATURE
322                 );
323             }
324         }
325     }
326 }
Popular Tags