KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > expression > ArgsIndexVisitor


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

30 public class ArgsIndexVisitor extends ExpressionVisitor {
31
32   /**
33    * Classloader used to perform type checks (for target / this bindings)
34    * A strong reference is enough since this visitor is not be referenced.
35    */

36   private ClassLoader JavaDoc m_classLoader;
37
38   /**
39    * Update the given context with its runtime information (this, target, args).
40    * It should be called for each advice.
41    *
42    * @param expressionInfo
43    * @param context
44    */

45   public static void updateContextForRuntimeInformation(final ExpressionInfo expressionInfo,
46                                                         final ExpressionContext context,
47                                                         final ClassLoader JavaDoc loader) {
48     ArgsIndexVisitor visitor = new ArgsIndexVisitor(
49             expressionInfo, expressionInfo.toString(),
50             expressionInfo.getNamespace(),
51             expressionInfo.getExpression().getASTRoot(),
52             loader
53     );
54     visitor.match(context);
55   }
56
57   private ArgsIndexVisitor(final ExpressionInfo expressionInfo,
58                            final String JavaDoc expression,
59                            final String JavaDoc namespace,
60                            final Node root,
61                            final ClassLoader JavaDoc loader) {
62     super(expressionInfo, expression, namespace, root);
63     m_classLoader = loader;
64   }
65
66   //-- overrided methods to compute the args index mapping --//
67

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

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

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