View Javadoc

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;
50  import java.util.ArrayList;
51  import java.util.Iterator;
52  import java.util.List;
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 m_expression;
73      protected String 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 expression,
90                               final String 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 match = ((Boolean) 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 matchUndeterministic(final ExpressionContext context) {
115         Boolean match = ((Boolean) visit(m_root, context));
116         return match;
117     }
118 
119     // ============ Boot strap =============
120     public Object visit(Node node, Object data) {
121         return node.jjtGetChild(0).jjtAccept(this, data);
122     }
123 
124     public Object visit(SimpleNode node, Object data) {
125         return node.jjtGetChild(0).jjtAccept(this, data);
126     }
127 
128     public Object visit(ASTRoot node, Object data) {
129         return node.jjtGetChild(0).jjtAccept(this, data);
130     }
131 
132     public Object visit(ASTExpression node, Object data) {
133         return node.jjtGetChild(0).jjtAccept(this, data);
134     }
135 
136     // ============ Logical operators =============
137     public Object visit(ASTOr node, Object data) {
138         // the AND and OR can have more than 2 nodes [see jjt grammar]
139         Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
140         Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
141         Boolean intermediate = Undeterministic.or(matchL, matchR);
142         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
143             Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
144             intermediate = Undeterministic.or(intermediate, matchNext);
145         }
146         return intermediate;
147     }
148 
149     public Object visit(ASTAnd node, Object data) {
150         // the AND and OR can have more than 2 nodes [see jjt grammar]
151         Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
152         Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
153         Boolean intermediate = Undeterministic.and(matchL, matchR);
154         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
155             Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
156             intermediate = Undeterministic.and(intermediate, matchNext);
157         }
158         return intermediate;
159     }
160 
161     public Object visit(ASTNot node, Object data) {
162         Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
163         return Undeterministic.not(match);
164     }
165 
166     // ============ Pointcut types =============
167     public Object visit(ASTPointcutReference node, Object 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 visit(ASTExecution node, Object 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 visit(ASTCall node, Object 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 visit(ASTSet node, Object 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 visit(ASTGet node, Object 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 visit(ASTHandler node, Object 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 visit(ASTStaticInitialization node, Object 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 matchPattern = (Boolean) 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 visit(ASTWithin node, Object 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 visit(ASTWithinCode node, Object 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 visit(ASTHasMethod node, Object 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 visit(ASTHasField node, Object 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 visit(ASTTarget node, Object 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 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 visit(ASTThis node, Object 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 visit(ASTCflow node, Object data) {
452         return null;
453     }
454 
455     public Object visit(ASTCflowBelow node, Object data) {
456         return null;
457     }
458 
459     // ============ Patterns =============
460     public Object visit(ASTClassPattern node, Object 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 visit(ASTMethodPattern node, Object 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 visit(ASTConstructorPattern node, Object 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 visit(ASTFieldPattern node, Object 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 visit(ASTParameter node, Object 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 visit(ASTArgs node, Object 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) 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) 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) 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) 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 visit(ASTArgParameter node, Object 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 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 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 visit(ASTAttribute node, Object data) {
696         boolean matchAnnotation = false;
697         List annotations = (List) data;
698         for (Iterator 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 visit(ASTModifier node, Object 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 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 parameterNodes = new ArrayList();
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) 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) 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) 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) 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 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 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)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 }