KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > expression > ArgsIndexVisitor


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.expression;
9
10 import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
11 import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
12 import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
13 import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
14 import org.codehaus.aspectwerkz.expression.ast.ASTThis;
15 import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
16 import org.codehaus.aspectwerkz.expression.ast.Node;
17 import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
18 import org.codehaus.aspectwerkz.util.Strings;
19 import org.codehaus.aspectwerkz.exception.DefinitionException;
20 import org.codehaus.aspectwerkz.reflect.ClassInfo;
21 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
22 import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
23 import org.codehaus.aspectwerkz.util.ContextClassLoader;
24
25 import java.util.Iterator JavaDoc;
26
27 import gnu.trove.TIntIntHashMap;
28 import gnu.trove.TObjectIntHashMap;
29
30 /**
31  * A visitor to compute the args index of the target (matching) method/constructor which match the advice args. Note:
32  * extends the ExpressionVisitor. We should allow for optimization (all=TRUE) by assuming that args(..) does not depends
33  * of the matching context. The "(String a, String b):methodX && args(a,b) -OR- methodY && args(b,a)" expression should
34  * not be allowed then.
35  *
36  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
37  */

38 public class ArgsIndexVisitor extends ExpressionVisitor {
39
40     /**
41      * Classloader used to perform type checks (for target / this bindings)
42      * A strong reference is enough since this visitor is not be referenced.
43      */

44     private ClassLoader JavaDoc m_classLoader;
45
46     /**
47      * Update the given context with its runtime information (this, target, args).
48      * It should be called for each advice.
49      *
50      * @param expressionInfo
51      * @param context
52      */

53     public static void updateContextForRuntimeInformation(final ExpressionInfo expressionInfo,
54                                                           final ExpressionContext context,
55                                                           final ClassLoader JavaDoc loader) {
56         ArgsIndexVisitor visitor = new ArgsIndexVisitor(
57                 expressionInfo, expressionInfo.toString(),
58                 expressionInfo.getNamespace(),
59                 expressionInfo.getExpression().getASTRoot(),
60                 loader
61         );
62         visitor.match(context);
63     }
64
65     private ArgsIndexVisitor(final ExpressionInfo expressionInfo,
66                              final String JavaDoc expression,
67                              final String JavaDoc namespace,
68                              final Node root,
69                              final ClassLoader JavaDoc loader) {
70         super(expressionInfo, expression, namespace, root);
71         m_classLoader = loader;
72     }
73
74     //-- overrided methods to compute the args index mapping --//
75

76     public Object JavaDoc visit(ASTPointcutReference node, Object JavaDoc data) {
77         // do the sub expression visit
78
ExpressionContext context = (ExpressionContext) data;
79         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
80         ExpressionInfo expressionInfo = namespace.getExpressionInfo(node.getName());
81
82         ArgsIndexVisitor referenced = new ArgsIndexVisitor(
83                 expressionInfo, expressionInfo.toString(),
84                 expressionInfo.getNamespace(),
85                 expressionInfo.getExpression().getASTRoot(),
86                 m_classLoader
87         );
88
89         // keep track of the state we already had
90
String JavaDoc targetSoFar = context.m_targetBoundedName;
91         String JavaDoc thisSoFar = context.m_thisBoundedName;
92         boolean targetWithRuntimeCheckSoFar = context.m_targetWithRuntimeCheck;
93         TObjectIntHashMap exprIndexToTargetIndexSoFar = (TObjectIntHashMap) context.m_exprIndexToTargetIndex.clone();
94
95         context.resetRuntimeState();
96         Boolean JavaDoc match = referenced.matchUndeterministic(context);
97
98         // merge the state
99
if (context.m_targetBoundedName == null) {
100             context.m_targetBoundedName = targetSoFar;
101         } else if (targetSoFar != null) {
102             if (node.jjtGetNumChildren() == 1) {
103                 String JavaDoc referenceCallArg = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().getPattern();
104                 if (!targetSoFar.equals(referenceCallArg)) {
105                     throw new UnsupportedOperationException JavaDoc("should not occur");
106                 }
107             }
108         }
109         if (context.m_thisBoundedName == null) {
110             context.m_thisBoundedName = thisSoFar;
111         } else if (thisSoFar != null) {
112             if (node.jjtGetNumChildren() == 1) {
113                 String JavaDoc referenceCallArg = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().getPattern();
114                 if (!thisSoFar.equals(referenceCallArg)) {
115                     throw new UnsupportedOperationException JavaDoc("should not occur");
116                 }
117             }
118         }
119         if (!context.m_targetWithRuntimeCheck) {
120             // restore
121
context.m_targetWithRuntimeCheck = targetWithRuntimeCheckSoFar;
122         }
123         if (context.m_exprIndexToTargetIndex.isEmpty()) {
124             // restore
125
context.m_exprIndexToTargetIndex = exprIndexToTargetIndexSoFar;
126         } else if (!exprIndexToTargetIndexSoFar.isEmpty()) {
127             //should merge ?
128
throw new UnsupportedOperationException JavaDoc("should not occur");
129         }
130
131
132         // update the this and target bounded name from this last visit as well as args
133
TObjectIntHashMap exprToTargetArgIndexes = new TObjectIntHashMap();
134         for (int i = 0; i < node.jjtGetNumChildren(); i++) {
135             String JavaDoc referenceCallArg = ((ASTArgParameter) node.jjtGetChild(i)).getTypePattern().getPattern();
136             String JavaDoc referentArg = expressionInfo.getArgumentNameAtIndex(i);
137             if (referentArg.equals(context.m_targetBoundedName)) {
138                 context.m_targetBoundedName = referenceCallArg;
139                 assertIsInstanceOf(
140                         expressionInfo.getArgumentType(referentArg),
141                         m_expressionInfo.getArgumentType(referenceCallArg)
142                 );
143             } else if (referentArg.equals(context.m_thisBoundedName)) {
144                 context.m_thisBoundedName = referenceCallArg;
145                 assertIsInstanceOf(
146                         expressionInfo.getArgumentType(referentArg),
147                         m_expressionInfo.getArgumentType(referenceCallArg)
148                 );
149             } else {
150                 int adviceArgIndex = i;
151                 if (context.m_exprIndexToTargetIndex.containsKey(referentArg)) {
152                     int targetArgIndex = context.m_exprIndexToTargetIndex.get(referentArg);
153                     exprToTargetArgIndexes.put(referenceCallArg, targetArgIndex);
154                 }
155
156             }
157         }
158         // merge with index found so far (inlined args() f.e.)
159
Object JavaDoc[] soFar = exprIndexToTargetIndexSoFar.keys();
160         for (int i = 0; i < soFar.length; i++) {
161             String JavaDoc name = (String JavaDoc) soFar[i];
162             if (!exprToTargetArgIndexes.containsKey(name)) {
163                 exprToTargetArgIndexes.put(name, exprIndexToTargetIndexSoFar.get(name));
164             }
165         }
166         context.m_exprIndexToTargetIndex = exprToTargetArgIndexes;
167         return match;
168     }
169
170     public Object JavaDoc visit(ASTCflow node, Object JavaDoc data) {
171         // do the sub expression visit
172
ExpressionContext context = (ExpressionContext) data;
173         //ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
174
//ExpressionInfo expressionInfo = namespace.getExpressionInfo(node.getName());
175

176         ExpressionInfo expressionInfo = new ExpressionInfo(
177                 node.jjtGetChild(0), m_namespace
178         );
179         expressionInfo.inheritPossibleArgumentFrom(m_expressionInfo);
180
181         ArgsIndexVisitor referenced = new ArgsIndexVisitor(
182                 expressionInfo, "N/A",
183                 m_namespace,
184                 node.jjtGetChild(0),
185                 m_classLoader
186         );
187
188         // keep track of the state we already had
189
String JavaDoc targetSoFar = context.m_targetBoundedName;
190         String JavaDoc thisSoFar = context.m_thisBoundedName;
191         boolean targetWithRuntimeCheckSoFar = context.m_targetWithRuntimeCheck;
192         TObjectIntHashMap exprIndexToTargetIndexSoFar = (TObjectIntHashMap) context.m_exprIndexToTargetIndex.clone();
193
194         context.resetRuntimeState();
195         Boolean JavaDoc match = referenced.matchUndeterministic(context);
196
197         // TODO FIX ME merge the state
198
if (context.m_targetBoundedName == null) {
199             context.m_targetBoundedName = targetSoFar;
200         } else if (targetSoFar != null) {
201             // cflow target
202
}
203         if (context.m_thisBoundedName == null) {
204             context.m_thisBoundedName = thisSoFar;
205         } else if (thisSoFar != null) {
206             // cflow this
207
}
208         if (!context.m_targetWithRuntimeCheck) {
209             // restore
210
context.m_targetWithRuntimeCheck = targetWithRuntimeCheckSoFar;
211         }
212         if (context.m_exprIndexToTargetIndex.isEmpty()) {
213             // restore
214
context.m_exprIndexToTargetIndex = exprIndexToTargetIndexSoFar;
215         } else if (!exprIndexToTargetIndexSoFar.isEmpty()) {
216             //should merge ?
217
for (int i = 0; i < exprIndexToTargetIndexSoFar.keys().length; i++) {
218                 Object JavaDoc o = exprIndexToTargetIndexSoFar.keys()[i];
219                 context.m_exprIndexToTargetIndex.put(o, exprIndexToTargetIndexSoFar.get(o));
220             }
221         }
222         return match;
223     }
224
225     public Object JavaDoc visit(ASTArgs node, Object JavaDoc data) {
226         return super.visit(node, data);
227     }
228
229     public Object JavaDoc visit(ASTArgParameter node, Object JavaDoc data) {
230         // do the visit
231
Boolean JavaDoc match = (Boolean JavaDoc) super.visit(node, data);
232
233         // get the pointcut signature arg index of the arg we are visiting
234
int pointcutArgIndex = -1;
235         if (node.getTypePattern().getPattern().indexOf(".") < 0) {
236             pointcutArgIndex = m_expressionInfo.getArgumentIndex(node.getTypePattern().getPattern());
237         }
238
239         // if match and we are visiting a parameter binding (not a type matching)
240
if (pointcutArgIndex >= 0 && Boolean.TRUE.equals(match)) {
241             ExpressionContext ctx = (ExpressionContext) data;
242             ctx.m_exprIndexToTargetIndex.put(
243                     m_expressionInfo.getArgumentNameAtIndex(pointcutArgIndex), ctx.getCurrentTargetArgsIndex()
244             );
245         }
246         return match;
247     }
248
249     public Object JavaDoc visit(ASTThis node, Object JavaDoc data) {
250         // if the this(..) node identifier appears in the pointcut signature, we have a bounded type
251
if (m_expressionInfo.getArgumentType(node.getIdentifier()) != null) {
252             ExpressionContext ctx = (ExpressionContext) data;
253             if (ctx.m_thisBoundedName == null) {
254                 ctx.m_thisBoundedName = node.getIdentifier();
255             } else if (ctx.m_thisBoundedName != node.getIdentifier()) {
256                 throw new DefinitionException(
257                         "this(..) seems to be bounded to different bounded entities in \""
258                         + m_expressionInfo.toString() + "\" in " +
259                         m_expressionInfo.getNamespace()
260                         + " : found " + ctx.m_targetBoundedName + " and " +
261                         node.getIdentifier()
262                 );
263             }
264         }
265         return super.visit(node, data);
266     }
267
268     public Object JavaDoc visit(ASTTarget node, Object JavaDoc data) {
269         // if the target(..) node identifier appears in the pointcut signature, we have a bounded type
270
if (m_expressionInfo.getArgumentType(node.getIdentifier()) != null) {
271             ExpressionContext ctx = (ExpressionContext) data;
272             if (ctx.m_targetBoundedName == null) {
273                 ctx.m_targetBoundedName = node.getIdentifier();
274             } else if (ctx.m_targetBoundedName != node.getIdentifier()) {
275                 throw new DefinitionException(
276                         "target(..) seems to be bounded to different bounded entities in \""
277                         + m_expressionInfo.toString() + "\" in " +
278                         m_expressionInfo.getNamespace()
279                         + " : found " + ctx.m_targetBoundedName + " and " +
280                         node.getIdentifier()
281                 );
282             }
283         }
284         // keep track if the result was undetermined: we will need a runtime check
285
Object JavaDoc match = super.visit(node, data);
286         if (match == null) {
287             ((ExpressionContext) data).m_targetWithRuntimeCheck = true;
288         }
289         return match;
290     }
291
292     /**
293      * Ensure className is an instance of superClass name (both super class / interface just like "instanceof")
294      * Or throw an exception
295      *
296      * @param className
297      * @param superClassName
298      */

299     private void assertIsInstanceOf(String JavaDoc className, String JavaDoc superClassName) {
300         if (className.equals(superClassName)) {
301             ;//fine
302
} else {
303             // advice(Foo f) for pc(f) with pc(Object o) for example
304
// we need to ensure that Foo is an instance of Object
305
ClassInfo classInfo = AsmClassInfo.getClassInfo(className, m_classLoader);
306             boolean instanceOf = ClassInfoHelper.instanceOf(classInfo, superClassName);
307             if (!instanceOf) {
308                 throw new DefinitionException(
309                         "Attempt to reference a pointcut with incompatible object type: for \""
310                         + m_expression + "\" , " + className + " is not an instance of " +
311                         superClassName +
312                         "."
313                         + " Error occured in " + m_namespace
314                 );
315             }
316         }
317     }
318 }
Popular Tags