KickJava   Java API By Example, From Geeks To Geeks.

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


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.annotation.AnnotationInfo;
11 import org.codehaus.aspectwerkz.expression.ast.ASTAnd;
12 import org.codehaus.aspectwerkz.expression.ast.ASTAttribute;
13 import org.codehaus.aspectwerkz.expression.ast.ASTCall;
14 import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
15 import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
16 import org.codehaus.aspectwerkz.expression.ast.ASTClassPattern;
17 import org.codehaus.aspectwerkz.expression.ast.ASTConstructorPattern;
18 import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
19 import org.codehaus.aspectwerkz.expression.ast.ASTExpression;
20 import org.codehaus.aspectwerkz.expression.ast.ASTFieldPattern;
21 import org.codehaus.aspectwerkz.expression.ast.ASTGet;
22 import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
23 import org.codehaus.aspectwerkz.expression.ast.ASTMethodPattern;
24 import org.codehaus.aspectwerkz.expression.ast.ASTModifier;
25 import org.codehaus.aspectwerkz.expression.ast.ASTNot;
26 import org.codehaus.aspectwerkz.expression.ast.ASTOr;
27 import org.codehaus.aspectwerkz.expression.ast.ASTParameter;
28 import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
29 import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
30 import org.codehaus.aspectwerkz.expression.ast.ASTSet;
31 import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
32 import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
33 import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
34 import org.codehaus.aspectwerkz.expression.ast.ExpressionParserVisitor;
35 import org.codehaus.aspectwerkz.expression.ast.Node;
36 import org.codehaus.aspectwerkz.expression.ast.SimpleNode;
37 import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
38 import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
39 import org.codehaus.aspectwerkz.expression.regexp.TypePattern;
40 import org.codehaus.aspectwerkz.reflect.ClassInfo;
41 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
42 import org.codehaus.aspectwerkz.reflect.FieldInfo;
43 import org.codehaus.aspectwerkz.reflect.MemberInfo;
44 import org.codehaus.aspectwerkz.reflect.MethodInfo;
45 import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
46 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
47 import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
48
49 import java.lang.reflect.Modifier JavaDoc;
50 import java.util.ArrayList JavaDoc;
51 import java.util.Iterator JavaDoc;
52 import java.util.List JavaDoc;
53
54 import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
55 import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
56 import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
57 import org.codehaus.aspectwerkz.expression.ast.ASTThis;
58 import org.codehaus.aspectwerkz.util.Util;
59
60 /**
61  * The expression visitor.
62  * If a runtime residual is required (target => instance of check sometimes), Undeterministic matching is used.
63  *
64  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
65  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
66  * @author Michael Nascimento
67  * @author <a HREF="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
68  */

69 public class ExpressionVisitor implements ExpressionParserVisitor {
70
71     protected Node m_root;
72     protected String JavaDoc m_expression;
73     protected String JavaDoc m_namespace;
74
75     /**
76      * The expressionInfo this visitor is built on
77      */

78     protected ExpressionInfo m_expressionInfo;
79
80     /**
81      * Creates a new expression.
82      *
83      * @param expressionInfo the expressionInfo this visitor is built on for expression with signature
84      * @param expression the expression as a string
85      * @param namespace the namespace
86      * @param root the AST root
87      */

88     public ExpressionVisitor(final ExpressionInfo expressionInfo,
89                              final String JavaDoc expression,
90                              final String JavaDoc namespace,
91                              final Node root) {
92         m_expressionInfo = expressionInfo;
93         m_expression = expression;
94         m_namespace = namespace;
95         m_root = root;
96     }
97
98     /**
99      * Matches the expression context.
100      * If undetermined, assume true.
101      * Do not use for poincut reference - see matchUndeterministic
102      *
103      * @param context
104      * @return
105      */

106     public boolean match(final ExpressionContext context) {
107         Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
108         // undeterministic is assumed to be "true" at this stage
109
// since it won't be composed anymore with a NOT (unless
110
// thru pointcut reference ie a new visitor)
111
return (match != null) ? match.booleanValue() : true;
112     }
113
114     protected Boolean JavaDoc matchUndeterministic(final ExpressionContext context) {
115         Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
116         return match;
117     }
118
119     // ============ Boot strap =============
120
public Object JavaDoc visit(Node node, Object JavaDoc data) {
121         return node.jjtGetChild(0).jjtAccept(this, data);
122     }
123
124     public Object JavaDoc visit(SimpleNode node, Object JavaDoc data) {
125         return node.jjtGetChild(0).jjtAccept(this, data);
126     }
127
128     public Object JavaDoc visit(ASTRoot node, Object JavaDoc data) {
129         return node.jjtGetChild(0).jjtAccept(this, data);
130     }
131
132     public Object JavaDoc visit(ASTExpression node, Object JavaDoc data) {
133         return node.jjtGetChild(0).jjtAccept(this, data);
134     }
135
136     // ============ Logical operators =============
137
public Object JavaDoc visit(ASTOr node, Object JavaDoc data) {
138         // the AND and OR can have more than 2 nodes [see jjt grammar]
139
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
140         Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
141         Boolean JavaDoc intermediate = Undeterministic.or(matchL, matchR);
142         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
143             Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
144             intermediate = Undeterministic.or(intermediate, matchNext);
145         }
146         return intermediate;
147     }
148
149     public Object JavaDoc visit(ASTAnd node, Object JavaDoc data) {
150         // the AND and OR can have more than 2 nodes [see jjt grammar]
151
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
152         Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
153         Boolean JavaDoc intermediate = Undeterministic.and(matchL, matchR);
154         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
155             Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
156             intermediate = Undeterministic.and(intermediate, matchNext);
157         }
158         return intermediate;
159     }
160
161     public Object JavaDoc visit(ASTNot node, Object JavaDoc data) {
162         Boolean JavaDoc match = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
163         return Undeterministic.not(match);
164     }
165
166     // ============ Pointcut types =============
167
public Object JavaDoc visit(ASTPointcutReference node, Object JavaDoc data) {
168         ExpressionContext context = (ExpressionContext) data;
169         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
170         ExpressionVisitor expression = namespace.getExpression(node.getName());
171         return expression.matchUndeterministic(context);
172     }
173
174     public Object JavaDoc visit(ASTExecution node, Object JavaDoc data) {
175         ExpressionContext context = (ExpressionContext) data;
176         if (context.hasExecutionPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
177             return visitAnnotatedNode(node, context.getReflectionInfo());
178         } else {
179             return Boolean.FALSE;
180         }
181     }
182
183     public Object JavaDoc visit(ASTCall node, Object JavaDoc data) {
184         ExpressionContext context = (ExpressionContext) data;
185         if (context.hasCallPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
186             return visitAnnotatedNode(node, context.getReflectionInfo());
187         } else {
188             return Boolean.FALSE;
189         }
190     }
191
192     public Object JavaDoc visit(ASTSet node, Object JavaDoc data) {
193         ExpressionContext context = (ExpressionContext) data;
194         if (context.hasSetPointcut() && context.hasFieldInfo()) {
195             return visitAnnotatedNode(node, context.getReflectionInfo());
196         } else {
197             return Boolean.FALSE;
198         }
199     }
200
201     public Object JavaDoc visit(ASTGet node, Object JavaDoc data) {
202         ExpressionContext context = (ExpressionContext) data;
203         if (context.hasGetPointcut() && context.hasFieldInfo()) {
204             return visitAnnotatedNode(node, context.getReflectionInfo());
205         } else {
206             return Boolean.FALSE;
207         }
208     }
209
210     public Object JavaDoc visit(ASTHandler node, Object JavaDoc data) {
211         ExpressionContext context = (ExpressionContext) data;
212         if (context.hasHandlerPointcut() && context.hasClassInfo()) {
213             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
214         } else {
215             return Boolean.FALSE;
216         }
217     }
218
219     public Object JavaDoc visit(ASTStaticInitialization node, Object JavaDoc data) {
220         ExpressionContext context = (ExpressionContext) data;
221         
222         if (context.hasStaticInitializationPointcut() && context.hasReflectionInfo()) {
223             ReflectionInfo reflectInfo = context.getReflectionInfo();
224             
225             if(reflectInfo instanceof StaticInitializationInfo) {
226                 ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
227
228                 // In an annotated subtree, only the last child node may represent the pattern
229
Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
230                 if (!(patternNode instanceof ASTAttribute)) {
231                     Boolean JavaDoc matchPattern = (Boolean JavaDoc) patternNode.jjtAccept(this, reflectInfo);
232                     if (Boolean.FALSE.equals(matchPattern)) {
233                         return Boolean.FALSE;
234                     }
235                 }
236
237                 // match on annotation if no pattern node or matched already
238
boolean matchedAnnotations = visitAttributes(node, declaringClassInfo);
239                 if (!matchedAnnotations) {
240                     return Boolean.FALSE;
241                 } else {
242                     return Boolean.TRUE;
243                 }
244             } else {
245                 return Boolean.FALSE;
246             }
247         } else {
248             return Boolean.FALSE;
249         }
250     }
251
252     public Object JavaDoc visit(ASTWithin node, Object JavaDoc data) {
253         ExpressionContext context = (ExpressionContext) data;
254         if (context.hasWithinReflectionInfo()) {
255             ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
256             ReflectionInfo withinInfo = null;
257             
258             if(reflectInfo instanceof MemberInfo) {
259                 withinInfo = ((MemberInfo) reflectInfo).getDeclaringType();
260             } else if(reflectInfo instanceof ClassInfo) {
261                 withinInfo = reflectInfo;
262             } else {
263                 return Boolean.FALSE;
264             }
265             return visitAnnotatedNode(
266                     node,
267                     withinInfo);
268         } else {
269             return null;
270         }
271     }
272
273     public Object JavaDoc visit(ASTWithinCode node, Object JavaDoc data) {
274         ExpressionContext context = (ExpressionContext) data;
275         
276         if(!context.hasWithinReflectionInfo()) {
277             return null;
278         }
279         
280         ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
281         
282         if(node.isStaticInitializer()) {
283             if(reflectInfo instanceof StaticInitializationInfo) {
284                 // Ignore the ASTStaticInitialization node in this context
285
SimpleNode staticClinitNode = (SimpleNode) node.jjtGetChild(0);
286                 ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
287                 
288                 boolean matchedAnnotations = visitAttributes(staticClinitNode, declaringClassInfo);
289                 if(!matchedAnnotations) {
290                     return Boolean.FALSE;
291                 }
292                 
293                 // In an annotated subtree, the last child node represents the pattern
294
Node lastNode = staticClinitNode.jjtGetChild(staticClinitNode.jjtGetNumChildren() - 1);
295                 if(lastNode instanceof ASTAttribute) {
296                     return Boolean.TRUE;
297                 } else {
298                     return lastNode.jjtAccept(this, reflectInfo);
299                 }
300             } else {
301                 return Boolean.FALSE;
302             }
303         } else {
304             return visitAnnotatedNode(
305                     node,
306                     reflectInfo
307                     );
308         }
309     }
310
311
312     public Object JavaDoc visit(ASTHasMethod node, Object JavaDoc data) {
313         ExpressionContext context = (ExpressionContext) data;
314
315         // we are matching on the CALLER info
316
// for execution() pointcut, this is equals to CALLEE info
317
ReflectionInfo info = context.getWithinReflectionInfo();
318         ClassInfo classInfo = info instanceof MemberInfo
319                 ? ((MemberInfo) info).getDeclaringType()
320                 : (ClassInfo) info;
321         
322         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
323         boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
324
325         MethodInfo[] methodInfos = classInfo.getMethods();
326         for (int i = 0; i < methodInfos.length; i++) {
327             if (hasPatternNode) {
328                 if(Boolean.FALSE.equals(patternNode.jjtAccept(this, methodInfos[i]))) {
329                     continue;
330                 }
331             }
332
333             boolean matchAnnotations = visitAttributes(node, methodInfos[i]);
334             if (matchAnnotations) {
335                 return Boolean.TRUE;
336             }
337         }
338
339         ConstructorInfo[] constructorInfos = classInfo.getConstructors();
340         for (int i = 0; i < constructorInfos.length; i++) {
341             if (hasPatternNode) {
342                 if(Boolean.FALSE.equals(patternNode.jjtAccept(this, constructorInfos[i]))) {
343                     continue;
344                 }
345             }
346
347             boolean matchAnnotations = visitAttributes(node, constructorInfos[i]);
348             if (matchAnnotations) {
349                 return Boolean.TRUE;
350             }
351         }
352
353         return Boolean.FALSE;
354     }
355
356     public Object JavaDoc visit(ASTHasField node, Object JavaDoc data) {
357         ExpressionContext context = (ExpressionContext) data;
358
359         // we are matching on the CALLER info
360
// for execution() pointcut, this is equals to CALLEE info
361
ReflectionInfo info = context.getWithinReflectionInfo();
362         ClassInfo classInfo = (info instanceof MemberInfo) ?
363                               ((MemberInfo) info).getDeclaringType() : (ClassInfo) info;
364
365         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
366         boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
367
368         FieldInfo[] fieldInfos = classInfo.getFields();
369         for (int i = 0; i < fieldInfos.length; i++) {
370             if (hasPatternNode) {
371                 if (Boolean.FALSE.equals(patternNode.jjtAccept(this, fieldInfos[i]))) {
372                     continue;
373                 }
374             }
375
376             boolean matchAnnotations = visitAttributes(node, fieldInfos[i]);
377             if (matchAnnotations) {
378                 return Boolean.TRUE;
379             }
380         }
381
382         return Boolean.FALSE;
383     }
384
385     public Object JavaDoc visit(ASTTarget node, Object JavaDoc data) {
386         ExpressionContext context = (ExpressionContext) data;
387         ReflectionInfo info = context.getReflectionInfo();
388
389 // //TODO - seems to be the case for AJ - not intuitive
390
// if (info instanceof ConstructorInfo) {
391
// // target(..) does not match for constructors
392
// return Boolean.FALSE;
393
// }
394
ClassInfo declaringType = null;
395         if (info instanceof MemberInfo) {
396             // if method/field is static, target(..) is evaluated to false
397
if (Modifier.isStatic(((MemberInfo) info).getModifiers())) {
398                 return Boolean.FALSE;
399             }
400
401             declaringType = ((MemberInfo) info).getDeclaringType();
402         } else if (info instanceof ClassInfo) {
403             declaringType = (ClassInfo) info;
404         } else {
405             return Boolean.FALSE;
406         }
407
408         String JavaDoc boundedTypeName = node.getBoundedType(m_expressionInfo);
409         // check if the context we match is an interface call, while the bounded type of target(..) is not an
410
// interface. In such a case we will need a runtime check
411
if (declaringType.isInterface()) {
412             // if we are a instanceof (subinterface) of the bounded type, then we don't need a runtime check
413
if (ClassInfoHelper.instanceOf(declaringType, boundedTypeName)) {
414                 return Boolean.TRUE;
415             } else {
416                 //System.out.println("*** RT check for " + boundedTypeName + " when I am " + declaringType.getName());
417
// a runtime check with instance of will be required
418
return null;
419             }
420         } else {
421             return Util.booleanValueOf(ClassInfoHelper.instanceOf(declaringType, boundedTypeName));
422         }
423     }
424
425     public Object JavaDoc visit(ASTThis node, Object JavaDoc data) {
426         ExpressionContext context = (ExpressionContext) data;
427         // for execution pointcut, this(..) is used to match the callee info
428
// and we are assuming here that withinInfo is properly set to reflectionInfo
429
if (context.hasWithinReflectionInfo()) {
430             ReflectionInfo withinInfo = context.getWithinReflectionInfo();
431             if (withinInfo instanceof MemberInfo) {
432                 // if method is static (callee for execution or caller for call/get/set), this(..) is evaluated to false
433
if (Modifier.isStatic(((MemberInfo) withinInfo).getModifiers())) {
434                     return Boolean.FALSE;
435                 }
436                 return Util.booleanValueOf(
437                         ClassInfoHelper.instanceOf(
438                                 ((MemberInfo) withinInfo).getDeclaringType(),
439                                 node.getBoundedType(m_expressionInfo)
440                         )
441                 );
442             } else if (withinInfo instanceof ClassInfo) {
443                 return Util.booleanValueOf(
444                         ClassInfoHelper.instanceOf((ClassInfo) withinInfo, node.getBoundedType(m_expressionInfo))
445                 );
446             }
447         }
448         return Boolean.FALSE;
449     }
450
451     public Object JavaDoc visit(ASTCflow node, Object JavaDoc data) {
452         return null;
453     }
454
455     public Object JavaDoc visit(ASTCflowBelow node, Object JavaDoc data) {
456         return null;
457     }
458
459     // ============ Patterns =============
460
public Object JavaDoc visit(ASTClassPattern node, Object JavaDoc data) {
461         if (data instanceof ClassInfo) {
462             ClassInfo classInfo = (ClassInfo) data;
463             TypePattern typePattern = node.getTypePattern();
464
465             if (typePattern.matchType(classInfo)
466                 && visitModifiers(node, classInfo)) {
467                 return Boolean.TRUE;
468             } else {
469                 return Boolean.FALSE;
470             }
471         } else if (data instanceof StaticInitializationInfo) {
472             ClassInfo classInfo = ((StaticInitializationInfo) data).getDeclaringType();
473             
474             if(node.getTypePattern().matchType(classInfo)) {
475                 return Boolean.TRUE;
476             } else {
477                 return Boolean.FALSE;
478             }
479             
480 // return new Boolean(node.getTypePattern().matchType(classInfo));
481
}
482         
483         return Boolean.FALSE;
484     }
485
486     public Object JavaDoc visit(ASTMethodPattern node, Object JavaDoc data) {
487         if (data instanceof MethodInfo) {
488             MethodInfo methodInfo = (MethodInfo) data;
489             if (node.getMethodNamePattern().matches(methodInfo.getName())
490                 && node.getDeclaringTypePattern().matchType(methodInfo.getDeclaringType())
491                 && node.getReturnTypePattern().matchType(methodInfo.getReturnType())
492                 && visitModifiers(node, methodInfo)
493                 && visitParameters(node, methodInfo.getParameterTypes())) {
494                 return Boolean.TRUE;
495             }
496         }
497
498         return Boolean.FALSE;
499     }
500
501     public Object JavaDoc visit(ASTConstructorPattern node, Object JavaDoc data) {
502         if (data instanceof ConstructorInfo) {
503             ConstructorInfo constructorMetaData = (ConstructorInfo) data;
504             if (node.getDeclaringTypePattern().matchType(constructorMetaData.getDeclaringType())
505                 && visitModifiers(node, constructorMetaData)
506                 && visitParameters(node, constructorMetaData.getParameterTypes())) {
507                 return Boolean.TRUE;
508             }
509         }
510         return Boolean.FALSE;
511     }
512
513     public Object JavaDoc visit(ASTFieldPattern node, Object JavaDoc data) {
514         if (data instanceof FieldInfo) {
515             FieldInfo fieldInfo = (FieldInfo) data;
516             if (node.getFieldNamePattern().matches(fieldInfo.getName())
517                 && node.getDeclaringTypePattern().matchType(fieldInfo.getDeclaringType())
518                 && node.getFieldTypePattern().matchType(fieldInfo.getType())
519                 && visitModifiers(node, fieldInfo)) {
520                 return Boolean.TRUE;
521             }
522         }
523         return Boolean.FALSE;
524     }
525
526     public Object JavaDoc visit(ASTParameter node, Object JavaDoc data) {
527         ClassInfo parameterType = (ClassInfo) data;
528         if (node.getDeclaringClassPattern().matchType(parameterType)) {
529             return Boolean.TRUE;
530         } else {
531             return Boolean.FALSE;
532         }
533     }
534
535     public Object JavaDoc visit(ASTArgs node, Object JavaDoc data) {
536         ExpressionContext ctx = (ExpressionContext) data;
537         if (node.jjtGetNumChildren() <= 0) {
538             // args(EMPTY)
539
return (getParametersCount(ctx) == 0) ? Boolean.TRUE : Boolean.FALSE;
540         } else {
541             // check for ".." as first node
542
int expressionParameterCount = node.jjtGetNumChildren();// the number of node minus eager one.
543
boolean isFirstArgEager = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().isEagerWildCard();
544             boolean isLastArgEager = ((ASTArgParameter) node.jjtGetChild(node.jjtGetNumChildren() - 1))
545                     .getTypePattern().isEagerWildCard();
546             // args(..)
547
if (isFirstArgEager && expressionParameterCount == 1) {
548                 return Boolean.TRUE;
549             }
550             int contextParametersCount = getParametersCount(ctx);
551             if (isFirstArgEager && isLastArgEager) {
552                 expressionParameterCount -= 2;
553                 if (expressionParameterCount == 0) {
554                     // expression is "args(.., ..)"
555
return Boolean.TRUE;
556                 }
557                 // we need to find a starting position - args(..,int, bar, ..)
558
// foo(int) //int is ok
559
// foo(bar,int,bar) //int is ok
560
// foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
561
int matchCount = 0;
562                 int ictx = 0;
563                 for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
564                     if (ictx >= contextParametersCount) {
565                         // too many args in args()
566
matchCount = -1;
567                         break;
568                     }
569                     ctx.setCurrentTargetArgsIndex(ictx);
570                     // do we have an eager wildcard in the middle ?
571
boolean isEager = ((ASTArgParameter) node.jjtGetChild(iexp + 1)).getTypePattern().isEagerWildCard();
572                     if (isEager) {
573                         // TODO - ignore for now, but not really supported - eager in the middle will match one
574
}
575                     if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(iexp + 1).jjtAccept(this, ctx))) {
576                         matchCount += 1;
577                         ictx++;
578                     } else {
579                         // assume matched by starting ".." and rewind expression index
580
matchCount = 0;
581                         ictx++;
582                         iexp = -1;
583                     }
584                 }
585                 if (matchCount == expressionParameterCount) {
586                     return Boolean.TRUE;
587                 } else {
588                     return Boolean.FALSE;
589                 }
590             } else if (isFirstArgEager) {
591                 expressionParameterCount--;
592                 if (contextParametersCount >= expressionParameterCount) {
593                     // do a match from last to first, break when args() nodes are exhausted
594
for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
595                         ctx.setCurrentTargetArgsIndex(contextParametersCount - 1 - i);
596                         if (Boolean.TRUE.equals(
597                                 (Boolean JavaDoc) node.jjtGetChild(expressionParameterCount - i).jjtAccept(
598                                         this,
599                                         ctx
600                                 )
601                         )) {
602                             ;//go on with "next" arg
603
} else {
604                             return Boolean.FALSE;
605                         }
606                     }
607                     return Boolean.TRUE;
608                 } else {
609                     //args() as more args than context we try to match
610
return Boolean.FALSE;
611                 }
612             } else if (isLastArgEager) {
613                 expressionParameterCount--;
614                 if (contextParametersCount >= expressionParameterCount) {
615                     // do a match from first to last, break when args() nodes are exhausted
616
for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
617                         ctx.setCurrentTargetArgsIndex(i);
618                         if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, ctx))) {
619                             ;//go on with next arg
620
} else {
621                             return Boolean.FALSE;
622                         }
623                     }
624                     return Boolean.TRUE;
625                 } else {
626                     return Boolean.FALSE;
627                 }
628             } else {
629                 // no eager wildcard in args()
630
// check that args length are equals
631
if (expressionParameterCount == contextParametersCount) {
632                     for (int i = 0; i < node.jjtGetNumChildren(); i++) {
633                         ctx.setCurrentTargetArgsIndex(i);
634                         if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, ctx))) {
635                             ;//go on with next arg
636
} else {
637                             return Boolean.FALSE;
638                         }
639                     }
640                     return Boolean.TRUE;
641                 } else {
642                     return Boolean.FALSE;
643                 }
644             }
645         }
646     }
647
648     public Object JavaDoc visit(ASTArgParameter node, Object JavaDoc data) {
649         //TODO we are not doing any hierarchical test when the arg is bound
650
// => args(e) and before(Exception e) will not mathch on catch(SubException e) ..
651
// is that required ? how AJ syntax behaves ?
652

653         TypePattern typePattern = node.getTypePattern();
654         TypePattern realPattern = typePattern;
655
656         // check if the arg is in the pointcut signature. In such a case, use the declared type
657
//TODO can we improve that with a lazy attach of the realTypePattern to the node
658
// and a method that always return the real pattern
659
// It must be lazy since args are not added at info ctor time [can be refactored..]
660
// do some filtering first to avoid unnecessary map lookup
661

662         int pointcutArgIndex = -1;
663         if (typePattern.getPattern().indexOf(".") < 0) {
664             String JavaDoc boundedType = m_expressionInfo.getArgumentType(typePattern.getPattern());
665             if (boundedType != null) {
666                 pointcutArgIndex = m_expressionInfo.getArgumentIndex(typePattern.getPattern());
667                 realPattern = TypePattern.compileTypePattern(boundedType, SubtypePatternType.NOT_HIERARCHICAL);
668             }
669         }
670         // grab parameter from context
671
ExpressionContext ctx = (ExpressionContext) data;
672         ClassInfo argInfo = null;
673         try {
674             if (ctx.getReflectionInfo() instanceof MethodInfo) {
675                 argInfo = ((MethodInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx.getCurrentTargetArgsIndex()];
676             } else if (ctx.getReflectionInfo() instanceof ConstructorInfo) {
677                 argInfo = ((ConstructorInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx
678                         .getCurrentTargetArgsIndex()];
679             } else if (ctx.getReflectionInfo() instanceof FieldInfo) {
680                 argInfo = ((FieldInfo) ctx.getReflectionInfo()).getType();
681             } else if (ctx.getPointcutType().equals(PointcutType.HANDLER) && ctx.getReflectionInfo() instanceof ClassInfo) {
682                 argInfo = (ClassInfo) ctx.getReflectionInfo();
683             }
684         } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
685             // ExpressionContext args are exhausted
686
return Boolean.FALSE;
687         }
688         if (realPattern.matchType(argInfo)) {
689             return Boolean.TRUE;
690         } else {
691             return Boolean.FALSE;
692         }
693     }
694
695     public Object JavaDoc visit(ASTAttribute node, Object JavaDoc data) {
696         boolean matchAnnotation = false;
697         List JavaDoc annotations = (List JavaDoc) data;
698         for (Iterator JavaDoc it = annotations.iterator(); it.hasNext();) {
699             AnnotationInfo annotation = (AnnotationInfo) it.next();
700             if (annotation.getName().equals(node.getName())) {
701                 matchAnnotation = true;
702             }
703         }
704         if (node.isNot()) {
705             return Util.booleanValueOf(!matchAnnotation);
706         } else {
707             return Util.booleanValueOf(matchAnnotation);
708         }
709     }
710
711     public Object JavaDoc visit(ASTModifier node, Object JavaDoc data) {
712         ReflectionInfo refInfo = (ReflectionInfo) data;
713         int modifiersToMatch = refInfo.getModifiers();
714         int modifierPattern = node.getModifier();
715         if (node.isNot()) {
716             if ((modifierPattern & Modifier.PUBLIC) != 0) {
717                 if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
718                     return Boolean.TRUE;
719                 } else {
720                     return Boolean.FALSE;
721                 }
722             } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
723                 if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
724                     return Boolean.TRUE;
725                 } else {
726                     return Boolean.FALSE;
727                 }
728             } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
729                 if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
730                     return Boolean.TRUE;
731                 } else {
732                     return Boolean.FALSE;
733                 }
734             } else if ((modifierPattern & Modifier.STATIC) != 0) {
735                 if ((modifiersToMatch & Modifier.STATIC) == 0) {
736                     return Boolean.TRUE;
737                 } else {
738                     return Boolean.FALSE;
739                 }
740             } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
741                 if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
742                     return Boolean.TRUE;
743                 } else {
744                     return Boolean.FALSE;
745                 }
746             } else if ((modifierPattern & Modifier.FINAL) != 0) {
747                 if ((modifiersToMatch & Modifier.FINAL) == 0) {
748                     return Boolean.TRUE;
749                 } else {
750                     return Boolean.FALSE;
751                 }
752             } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
753                 if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
754                     return Boolean.TRUE;
755                 } else {
756                     return Boolean.FALSE;
757                 }
758             } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
759                 if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
760                     return Boolean.TRUE;
761                 } else {
762                     return Boolean.FALSE;
763                 }
764             } else if ((modifierPattern & Modifier.STRICT) != 0) {
765                 if ((modifiersToMatch & Modifier.STRICT) == 0) {
766                     return Boolean.TRUE;
767                 } else {
768                     return Boolean.FALSE;
769                 }
770             } else {
771                 return Boolean.FALSE;
772             }
773         } else {
774             if ((modifierPattern & Modifier.PUBLIC) != 0) {
775                 if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
776                     return Boolean.FALSE;
777                 } else {
778                     return Boolean.TRUE;
779                 }
780             } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
781                 if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
782                     return Boolean.FALSE;
783                 } else {
784                     return Boolean.TRUE;
785                 }
786             } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
787                 if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
788                     return Boolean.FALSE;
789                 } else {
790                     return Boolean.TRUE;
791                 }
792             } else if ((modifierPattern & Modifier.STATIC) != 0) {
793                 if ((modifiersToMatch & Modifier.STATIC) == 0) {
794                     return Boolean.FALSE;
795                 } else {
796                     return Boolean.TRUE;
797                 }
798             } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
799                 if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
800                     return Boolean.FALSE;
801                 } else {
802                     return Boolean.TRUE;
803                 }
804             } else if ((modifierPattern & Modifier.FINAL) != 0) {
805                 if ((modifiersToMatch & Modifier.FINAL) == 0) {
806                     return Boolean.FALSE;
807                 } else {
808                     return Boolean.TRUE;
809                 }
810             } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
811                 if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
812                     return Boolean.FALSE;
813                 } else {
814                     return Boolean.TRUE;
815                 }
816             } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
817                 if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
818                     return Boolean.FALSE;
819                 } else {
820                     return Boolean.TRUE;
821                 }
822             } else if ((modifierPattern & Modifier.STRICT) != 0) {
823                 if ((modifiersToMatch & Modifier.STRICT) == 0) {
824                     return Boolean.FALSE;
825                 } else {
826                     return Boolean.TRUE;
827                 }
828             } else {
829                 return Boolean.TRUE;
830             }
831         }
832     }
833
834     protected boolean visitAttributes(SimpleNode node, ReflectionInfo refInfo) {
835         int nrChildren = node.jjtGetNumChildren();
836         if (nrChildren != 0) {
837             for (int i = 0; i < nrChildren; i++) {
838                 Node child = node.jjtGetChild(i);
839                 if (child instanceof ASTAttribute) {
840                     List JavaDoc annotations = refInfo.getAnnotations();
841                     if (Boolean.TRUE.equals(child.jjtAccept(this, annotations))) {
842                         continue;
843                     } else {
844                         return false;
845                     }
846                 }
847             }
848         }
849         return true;
850     }
851
852     protected boolean visitModifiers(SimpleNode node, ReflectionInfo refInfo) {
853         int nrChildren = node.jjtGetNumChildren();
854         if (nrChildren != 0) {
855             for (int i = 0; i < nrChildren; i++) {
856                 Node child = node.jjtGetChild(i);
857                 if (child instanceof ASTModifier) {
858                     if (Boolean.TRUE.equals(child.jjtAccept(this, refInfo))) {
859                         continue;
860                     } else {
861                         return false;
862                     }
863                 }
864             }
865         }
866         return true;
867     }
868
869     protected boolean visitParameters(SimpleNode node, ClassInfo[] parameterTypes) {
870         int nrChildren = node.jjtGetNumChildren();
871         if (nrChildren <= 0) {
872             return (parameterTypes.length == 0);
873         }
874
875         // collect the parameter nodes
876
List JavaDoc parameterNodes = new ArrayList JavaDoc();
877         for (int i = 0; i < nrChildren; i++) {
878             Node child = node.jjtGetChild(i);
879             if (child instanceof ASTParameter) {
880                 parameterNodes.add(child);
881             }
882         }
883
884         if (parameterNodes.size() <= 0) {
885             return (parameterTypes.length == 0);
886         }
887
888         //TODO duplicate code with args() match
889
//TODO refactor parameterNodes in an array for faster match
890

891         // look for eager pattern at the beginning and end
892
int expressionParameterCount = parameterNodes.size();
893         boolean isFirstArgEager = ((ASTParameter) parameterNodes.get(0)).getDeclaringClassPattern().isEagerWildCard();
894         boolean isLastArgEager = ((ASTParameter) parameterNodes.get(expressionParameterCount - 1)).getDeclaringClassPattern()
895                 .isEagerWildCard();
896         // foo(..)
897
if (isFirstArgEager && expressionParameterCount == 1) {
898             return true;
899         }
900         int contextParametersCount = parameterTypes.length;
901         if (isFirstArgEager && isLastArgEager) {
902             expressionParameterCount -= 2;
903             if (expressionParameterCount == 0) {
904                 // foo(.., ..)
905
return true;
906             }
907             // we need to find a starting position - foo(..,int, bar, ..)
908
// foo(int) //int is ok
909
// foo(bar,int,bar) //int is ok
910
// foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
911
int matchCount = 0;
912             int ictx = 0;
913             for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
914                 if (ictx >= contextParametersCount) {
915                     // too many args in foo()
916
matchCount = -1;
917                     break;
918                 }
919                 // do we have an eager wildcard in the middle ?
920
ASTParameter parameterNode = (ASTParameter) parameterNodes.get(iexp + 1);
921                 boolean isEager = parameterNode.getDeclaringClassPattern().isEagerWildCard();
922                 if (isEager) {
923                     // TODO - ignore for now, but not really supported - eager in the middle will match one
924
}
925                 if (Boolean.TRUE.equals((Boolean JavaDoc) parameterNode.jjtAccept(this, parameterTypes[ictx]))) {
926                     matchCount += 1;
927                     ictx++;
928                 } else {
929                     // assume matched by starting ".." and rewind expression index
930
matchCount = 0;
931                     ictx++;
932                     iexp = -1;
933                 }
934             }
935             if (matchCount == expressionParameterCount) {
936                 return true;
937             } else {
938                 return false;
939             }
940         } else if (isFirstArgEager) {
941             expressionParameterCount--;
942             if (contextParametersCount >= expressionParameterCount) {
943                 // do a match from last to first, break when foo() nodes are exhausted
944
for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
945                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(expressionParameterCount - i);
946                     if (Boolean.TRUE.equals(
947                             (Boolean JavaDoc) parameterNode.jjtAccept(
948                                     this,
949                                     parameterTypes[contextParametersCount - 1 - i]
950                             )
951                     )) {
952                         ;//go on with "next" param
953
} else {
954                         return false;
955                     }
956                 }
957                 return true;
958             } else {
959                 //foo() as more param than context we try to match
960
return false;
961             }
962         } else if (isLastArgEager) {
963             expressionParameterCount--;
964             if (contextParametersCount >= expressionParameterCount) {
965                 // do a match from first to last, break when foo() nodes are exhausted
966
for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
967                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
968                     if (Boolean.TRUE.equals((Boolean JavaDoc) parameterNode.jjtAccept(this, parameterTypes[i]))) {
969                         ;//go on with next param
970
} else {
971                         return false;
972                     }
973                 }
974                 return true;
975             } else {
976                 return false;
977             }
978         } else {
979             // no eager wildcard in foo()
980
// check that param length are equals
981
if (expressionParameterCount == contextParametersCount) {
982                 for (int i = 0; i < parameterNodes.size(); i++) {
983                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
984                     if (Boolean.TRUE.equals((Boolean JavaDoc) parameterNode.jjtAccept(this, parameterTypes[i]))) {
985                         ;//go on with next param
986
} else {
987                         return false;
988                     }
989                 }
990                 return true;
991             } else {
992                 return false;
993             }
994         }
995     }
996
997     /**
998      * Returns the string representation of the expression.
999      *
1000     * @return
1001     */

1002    public String JavaDoc toString() {
1003        return m_expression;
1004    }
1005
1006    /**
1007     * Returns the number of parameters to the target method/constructor else -1.
1008     *
1009     * @param ctx
1010     * @return
1011     */

1012    private int getParametersCount(final ExpressionContext ctx) {
1013        ReflectionInfo reflectionInfo = ctx.getReflectionInfo();
1014        if (reflectionInfo instanceof MethodInfo) {
1015            return ((MethodInfo) reflectionInfo).getParameterTypes().length;
1016        } else if (reflectionInfo instanceof ConstructorInfo) {
1017            return ((ConstructorInfo) reflectionInfo).getParameterTypes().length;
1018        } else if (reflectionInfo instanceof FieldInfo) {
1019            return 1;//field set support for args()
1020
} else if (ctx.getPointcutType().equals(PointcutType.HANDLER) && reflectionInfo instanceof ClassInfo) {
1021            // handler args(e) binding
1022
return 1;
1023        } else {
1024            return -1;
1025        }
1026    }
1027
1028    /**
1029     * Test the context upon the expression tree, under a node that can
1030     * contain annotations.
1031     *
1032     * @param node root node of the annotation expression
1033     * @param reflectInfo context reflection info
1034     *
1035     * @return <CODE>Boolean.TRUE</CODE> in case the <tt>reflectInfo</tt> match
1036     * the expression subtree, <CODE>Boolean.FALSE</CODE> otherwise.
1037     */

1038    protected Object JavaDoc visitAnnotatedNode(SimpleNode node,
1039                                        ReflectionInfo reflectInfo) {
1040        // In an annotated subtree, only the last child node may represent the pattern
1041
Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
1042        if (!(patternNode instanceof ASTAttribute)) {
1043            if (Boolean.FALSE.equals((Boolean JavaDoc)patternNode.jjtAccept(this, reflectInfo))) {
1044                return Boolean.FALSE;
1045            }
1046        }
1047
1048        boolean matchedAnnotations = visitAttributes(node, reflectInfo);
1049        if (!matchedAnnotations) {
1050            return Boolean.FALSE;
1051        } else {
1052            return Boolean.TRUE;
1053        }
1054    }
1055
1056    /**
1057     * Access the ASTRoot we visit
1058     *
1059     * @return
1060     */

1061    public Node getASTRoot() {
1062        return m_root;
1063    }
1064
1065    /**
1066     * Access the ExpressionInfo we are build on
1067     *
1068     * @return
1069     */

1070    public ExpressionInfo getExpressionInfo() {
1071        return m_expressionInfo;
1072    }
1073}
1074
Popular Tags