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.ClassInfoHelper;
42  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
43  import org.codehaus.aspectwerkz.reflect.FieldInfo;
44  import org.codehaus.aspectwerkz.reflect.MemberInfo;
45  import org.codehaus.aspectwerkz.reflect.MethodInfo;
46  import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
47  
48  import java.lang.reflect.Modifier;
49  import java.util.ArrayList;
50  import java.util.Iterator;
51  import java.util.List;
52  import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
53  import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
54  
55  /***
56   * The expression visitor.
57   * 
58   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
59   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
60   * @author Michael Nascimento
61   */
62  public class ExpressionVisitor implements ExpressionParserVisitor {
63  
64      protected ASTRoot m_root;
65      protected String m_expression;
66      protected String m_namespace;
67  
68      /***
69       * The expressionInfo this visitor is built on for expression with signature Caution: Can be null for visitor that
70       * don't need this information.
71       */
72      protected ExpressionInfo m_expressionInfo;
73  
74      /***
75       * Creates a new expression.
76       * 
77       * @param expressionInfo the expressionInfo this visitor is built on for expression with signature
78       * @param expression the expression as a string
79       * @param namespace the namespace
80       * @param root the AST root
81       */
82      public ExpressionVisitor(final ExpressionInfo expressionInfo,
83                               final String expression,
84                               final String namespace,
85                               final ASTRoot root) {
86          m_expressionInfo = expressionInfo;
87          m_expression = expression;
88          m_namespace = namespace;
89          m_root = root;
90      }
91  
92      /***
93       * Matches the expression context.
94       * 
95       * @param context
96       * @return
97       */
98      public boolean match(final ExpressionContext context) {
99          return ((Boolean) visit(m_root, context)).booleanValue();
100     }
101 
102     // ============ Boot strap =============
103     public Object visit(SimpleNode node, Object data) {
104         return node.jjtGetChild(0).jjtAccept(this, data);
105     }
106 
107     public Object visit(ASTRoot node, Object data) {
108         return node.jjtGetChild(0).jjtAccept(this, data);
109     }
110 
111     public Object visit(ASTExpression node, Object data) {
112         return node.jjtGetChild(0).jjtAccept(this, data);
113     }
114 
115     // ============ Logical operators =============
116     public Object visit(ASTOr node, Object data) {
117         int nrOfChildren = node.jjtGetNumChildren();
118         for (int i = 0; i < nrOfChildren; i++) {
119             Boolean match = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
120             if (match.equals(Boolean.TRUE)) {
121                 return Boolean.TRUE;
122             }
123         }
124         return Boolean.FALSE;
125     }
126 
127     public Object visit(ASTAnd node, Object data) {
128         int nrOfChildren = node.jjtGetNumChildren();
129         for (int i = 0; i < nrOfChildren; i++) {
130             Boolean match = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
131             if (match.equals(Boolean.FALSE)) {
132                 return Boolean.FALSE;
133             }
134         }
135         return Boolean.TRUE;
136     }
137 
138     public Object visit(ASTNot node, Object data) {
139         Node child = node.jjtGetChild(0);
140         Boolean match = (Boolean) child.jjtAccept(this, data);
141         if (child instanceof ASTCflow || child instanceof ASTCflowBelow) {
142             return match;
143         } else {
144             if (match.equals(Boolean.TRUE)) {
145                 return Boolean.FALSE;
146             } else {
147                 return Boolean.TRUE;
148             }
149         }
150     }
151 
152     // ============ Pointcut types =============
153     public Object visit(ASTPointcutReference node, Object data) {
154         ExpressionContext context = (ExpressionContext) data;
155         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
156         ExpressionVisitor expression = namespace.getExpression(node.getName());
157         return new Boolean(expression.match(context));
158     }
159 
160     public Object visit(ASTExecution node, Object data) {
161         ExpressionContext context = (ExpressionContext) data;
162         if (context.hasExecutionPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
163             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
164         } else {
165             return Boolean.FALSE;
166         }
167     }
168 
169     public Object visit(ASTCall node, Object data) {
170         ExpressionContext context = (ExpressionContext) data;
171         if (context.hasCallPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
172             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
173         } else {
174             return Boolean.FALSE;
175         }
176     }
177 
178     public Object visit(ASTSet node, Object data) {
179         ExpressionContext context = (ExpressionContext) data;
180         if (context.hasSetPointcut() && context.hasFieldInfo()) {
181             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
182         } else {
183             return Boolean.FALSE;
184         }
185     }
186 
187     public Object visit(ASTGet node, Object data) {
188         ExpressionContext context = (ExpressionContext) data;
189         if (context.hasGetPointcut() && context.hasFieldInfo()) {
190             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
191         } else {
192             return Boolean.FALSE;
193         }
194     }
195 
196     public Object visit(ASTHandler node, Object data) {
197         ExpressionContext context = (ExpressionContext) data;
198         if (context.hasHandlerPointcut() && context.hasClassInfo()) {
199             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
200         } else {
201             return Boolean.FALSE;
202         }
203     }
204 
205     public Object visit(ASTStaticInitialization node, Object data) {
206         ExpressionContext context = (ExpressionContext) data;
207         if (context.hasStaticInitializationPointcut() && context.hasClassInfo()) {
208             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
209         } else {
210             return Boolean.FALSE;
211         }
212     }
213 
214     public Object visit(ASTWithin node, Object data) {
215         ExpressionContext context = (ExpressionContext) data;
216         if (context.hasWithinReflectionInfo()) {
217             ReflectionInfo withinInfo = context.getWithinReflectionInfo();
218             if (withinInfo instanceof MemberInfo) {
219                 return node.jjtGetChild(0).jjtAccept(this, ((MemberInfo) withinInfo).getDeclaringType());
220             } else if (withinInfo instanceof ClassInfo) {
221                 return node.jjtGetChild(0).jjtAccept(this, withinInfo);
222             }
223         }
224         return Boolean.FALSE;
225     }
226 
227     public Object visit(ASTWithinCode node, Object data) {
228         ExpressionContext context = (ExpressionContext) data;
229         if (context.hasWithinReflectionInfo()) {
230             return node.jjtGetChild(0).jjtAccept(this, context.getWithinReflectionInfo());
231         } else {
232             return Boolean.FALSE;
233         }
234     }
235 
236 
237     public Object visit(ASTHasMethod node, Object data) {
238         ExpressionContext context = (ExpressionContext) data;
239 
240         // we are matching on the CALLER info
241         // for execution() pointcut, this is equals to CALLEE info
242         ReflectionInfo info = context.getWithinReflectionInfo();
243         ClassInfo classInfo = (info instanceof MemberInfo) ?
244             ((MemberInfo)info).getDeclaringType() : (ClassInfo)info;
245 
246         Node childNode = node.jjtGetChild(0);
247         MethodInfo[] methodInfos = classInfo.getMethods();
248         for (int i = 0; i < methodInfos.length; i++) {
249             if (Boolean.TRUE.equals(childNode.jjtAccept(this, methodInfos[i]))) {
250                 return Boolean.TRUE;
251             }
252         }
253 
254         ConstructorInfo[] constructorInfos = classInfo.getConstructors();
255         for (int i = 0; i < constructorInfos.length; i++) {
256             if (Boolean.TRUE.equals(childNode.jjtAccept(this, constructorInfos[i]))) {
257                 return Boolean.TRUE;
258             }
259         }
260 
261         return Boolean.FALSE;
262     }
263 
264     public Object visit(ASTHasField node, Object data) {
265         ExpressionContext context = (ExpressionContext) data;
266 
267         // we are matching on the CALLER info
268         // for execution() pointcut, this is equals to CALLEE info
269         ReflectionInfo info = context.getWithinReflectionInfo();
270         ClassInfo classInfo = (info instanceof MemberInfo) ?
271             ((MemberInfo)info).getDeclaringType() : (ClassInfo)info;
272 
273         Node childNode = node.jjtGetChild(0);
274         FieldInfo[] fieldInfos = classInfo.getFields();
275         for (int i = 0; i < fieldInfos.length; i++) {
276             if (Boolean.TRUE.equals(childNode.jjtAccept(this, fieldInfos[i]))) {
277                 return Boolean.TRUE;
278             }
279         }
280 
281         return Boolean.FALSE;
282     }
283 
284     public Object visit(ASTCflow node, Object data) {
285         return Boolean.TRUE;
286     }
287 
288     public Object visit(ASTCflowBelow node, Object data) {
289         return Boolean.TRUE;
290     }
291 
292     // ============ Patterns =============
293     public Object visit(ASTClassPattern node, Object data) {
294         ClassInfo classInfo = (ClassInfo) data;
295         TypePattern typePattern = node.getTypePattern();
296         if (ClassInfoHelper.matchType(typePattern, classInfo)
297             && visitAttributes(node, classInfo)
298             && visitModifiers(node, classInfo)) {
299             return Boolean.TRUE;
300         } else {
301             return Boolean.FALSE;
302         }
303     }
304 
305     public Object visit(ASTMethodPattern node, Object data) {
306         if (data instanceof MethodInfo) {
307             MethodInfo methodInfo = (MethodInfo) data;
308             if (node.getMethodNamePattern().matches(methodInfo.getName())
309                 && ClassInfoHelper.matchType(node.getDeclaringTypePattern(), methodInfo.getDeclaringType())
310                 && ClassInfoHelper.matchType(node.getReturnTypePattern(), methodInfo.getReturnType())
311                 && visitAttributes(node, methodInfo)
312                 && visitModifiers(node, methodInfo)
313                 && visitParameters(node, methodInfo.getParameterTypes())) {
314                 return Boolean.TRUE;
315             }
316         }
317 
318         return Boolean.FALSE;
319     }
320 
321     public Object visit(ASTConstructorPattern node, Object data) {
322         if (data instanceof ConstructorInfo) {
323             ConstructorInfo constructorMetaData = (ConstructorInfo) data;
324             if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), constructorMetaData.getDeclaringType())
325                 && visitAttributes(node, constructorMetaData)
326                 && visitModifiers(node, constructorMetaData)
327                 && visitParameters(node, constructorMetaData.getParameterTypes())) {
328                 return Boolean.TRUE;
329             }
330         }
331         return Boolean.FALSE;
332     }
333 
334     public Object visit(ASTFieldPattern node, Object data) {
335         if (data instanceof FieldInfo) {
336             FieldInfo fieldInfo = (FieldInfo) data;
337             if (node.getFieldNamePattern().matches(fieldInfo.getName())
338                 && ClassInfoHelper.matchType(node.getDeclaringTypePattern(), fieldInfo.getDeclaringType())
339                 && ClassInfoHelper.matchType(node.getFieldTypePattern(), fieldInfo.getType())
340                 && visitAttributes(node, fieldInfo)
341                 && visitModifiers(node, fieldInfo)) {
342                 return Boolean.TRUE;
343             }
344         }
345         return Boolean.FALSE;
346     }
347 
348     public Object visit(ASTParameter node, Object data) {
349         ClassInfo parameterType = (ClassInfo) data;
350         if (ClassInfoHelper.matchType(node.getDeclaringClassPattern(), parameterType)) {
351             return Boolean.TRUE;
352         } else {
353             return Boolean.FALSE;
354         }
355     }
356 
357     public Object visit(ASTArgs node, Object data) {
358         ExpressionContext ctx = (ExpressionContext) data;
359         if (node.jjtGetNumChildren() <= 0) {
360             // args(EMPTY)
361             return (getParametersCount(ctx) == 0) ? Boolean.TRUE : Boolean.FALSE;
362         } else {
363             // check for ".." as first node
364             int expressionParameterCount = node.jjtGetNumChildren();// the number of node minus eager one.
365             boolean isFirstArgEager = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().isEagerWildCard();
366             boolean isLastArgEager = ((ASTArgParameter) node.jjtGetChild(node.jjtGetNumChildren() - 1))
367                     .getTypePattern().isEagerWildCard();
368             // args(..)
369             if (isFirstArgEager && expressionParameterCount == 1) {
370                 return Boolean.TRUE;
371             }
372             int contextParametersCount = getParametersCount(ctx);
373             if (isFirstArgEager && isLastArgEager) {
374                 expressionParameterCount -= 2;
375                 if (expressionParameterCount == 0) {
376                     // expression is "args(.., ..)"
377                     return Boolean.TRUE;
378                 }
379                 // we need to find a starting position - args(..,int, bar, ..)
380                 // foo(int) //int is ok
381                 // foo(bar,int,bar) //int is ok
382                 // foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
383                 int matchCount = 0;
384                 int ictx = 0;
385                 for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
386                     if (ictx >= contextParametersCount) {
387                         // too many args in args()
388                         matchCount = -1;
389                         break;
390                     }
391                     ctx.setCurrentTargetArgsIndex(ictx);
392                     // do we have an eager wildcard in the middle ?
393                     boolean isEager = ((ASTArgParameter) node.jjtGetChild(iexp+1)).getTypePattern().isEagerWildCard();
394                     if (isEager) {
395                         // TODO - ignore for now, but not really supported - eager in the middle will match one
396                     }
397                     if (Boolean.TRUE.equals((Boolean) node.jjtGetChild(iexp+1).jjtAccept(this, ctx))) {
398                         matchCount += 1;
399                         ictx++;
400                     } else {
401                         // assume matched by starting ".." and rewind expression index
402                         matchCount = 0;
403                         ictx++;
404                         iexp = -1;
405                     }
406                 }
407                 if (matchCount == expressionParameterCount) {
408                     return Boolean.TRUE;
409                 } else {
410                     return Boolean.FALSE;
411                 }
412             } else if (isFirstArgEager) {
413                 expressionParameterCount--;
414                 if (contextParametersCount >= expressionParameterCount) {
415                     // do a match from last to first, break when args() nodes are exhausted
416                     for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
417                         ctx.setCurrentTargetArgsIndex(contextParametersCount - 1 - i);
418                         if (Boolean.TRUE.equals((Boolean) node.jjtGetChild(expressionParameterCount - i).jjtAccept(
419                             this,
420                             ctx))) {
421                             ;//go on with "next" arg
422                         } else {
423                             return Boolean.FALSE;
424                         }
425                     }
426                     return Boolean.TRUE;
427                 } else {
428                     //args() as more args than context we try to match
429                     return Boolean.FALSE;
430                 }
431             } else if (isLastArgEager) {
432                 expressionParameterCount--;
433                 if (contextParametersCount >= expressionParameterCount) {
434                     // do a match from first to last, break when args() nodes are exhausted
435                     for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
436                         ctx.setCurrentTargetArgsIndex(i);
437                         if (Boolean.TRUE.equals((Boolean) node.jjtGetChild(i).jjtAccept(this, ctx))) {
438                             ;//go on with next arg
439                         } else {
440                             return Boolean.FALSE;
441                         }
442                     }
443                     return Boolean.TRUE;
444                 } else {
445                     return Boolean.FALSE;
446                 }
447             } else {
448                 // no eager wildcard in args()
449                 // check that args length are equals
450                 if (expressionParameterCount == contextParametersCount) {
451                     for (int i = 0; i < node.jjtGetNumChildren(); i++) {
452                         ctx.setCurrentTargetArgsIndex(i);
453                         if (Boolean.TRUE.equals((Boolean) node.jjtGetChild(i).jjtAccept(this, ctx))) {
454                             ;//go on with next arg
455                         } else {
456                             return Boolean.FALSE;
457                         }
458                     }
459                     return Boolean.TRUE;
460                 } else {
461                     return Boolean.FALSE;
462                 }
463             }
464         }
465     }
466 
467     public Object visit(ASTArgParameter node, Object data) {
468         TypePattern typePattern = node.getTypePattern();
469         TypePattern realPattern = typePattern;
470 
471         // check if the arg is in the pointcut signature. In such a case, use the declared type
472         //TODO can we improve that with a lazy attach of the realTypePattern to the node
473         // and a method that always return the real pattern
474         // It must be lazy since args are not added at info ctor time [can be refactored..]
475         // do some filtering first to avoid unnecessary map lookup
476         
477         int pointcutArgIndex = -1;
478         if (typePattern.getPattern().indexOf(".") < 0) {
479             String boundedType = m_expressionInfo.getArgumentType(typePattern.getPattern());
480             if (boundedType != null) {
481                 pointcutArgIndex = m_expressionInfo.getArgumentIndex(typePattern.getPattern());
482                 realPattern = TypePattern.compileTypePattern(boundedType, SubtypePatternType.NOT_HIERARCHICAL);
483             }
484         }
485         // grab parameter from context
486         ExpressionContext ctx = (ExpressionContext) data;
487         ClassInfo argInfo = null;
488         try {
489             if (ctx.getReflectionInfo() instanceof MethodInfo) {
490                 argInfo = ((MethodInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx.getCurrentTargetArgsIndex()];
491             } else if (ctx.getReflectionInfo() instanceof ConstructorInfo) {
492                 argInfo = ((ConstructorInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx
493                         .getCurrentTargetArgsIndex()];
494             } else if (ctx.getReflectionInfo() instanceof FieldInfo) {
495                 argInfo = ((FieldInfo) ctx.getReflectionInfo()).getType();
496             }
497         } catch (ArrayIndexOutOfBoundsException e) {
498             // ExpressionContext args are exhausted
499             return Boolean.FALSE;
500         }
501         if (ClassInfoHelper.matchType(realPattern, argInfo)) {
502             return Boolean.TRUE;
503         } else {
504             return Boolean.FALSE;
505         }
506     }
507 
508     public Object visit(ASTAttribute node, Object data) {
509         List annotations = (List) data;
510         for (Iterator it = annotations.iterator(); it.hasNext();) {
511             AnnotationInfo annotation = (AnnotationInfo) it.next();
512             if (annotation.getName().equals(node.getName())) {
513                 return Boolean.TRUE;
514             }
515         }
516         return Boolean.FALSE;
517     }
518 
519     public Object visit(ASTModifier node, Object data) {
520         ReflectionInfo refInfo = (ReflectionInfo) data;
521         int modifiersToMatch = refInfo.getModifiers();
522         int modifierPattern = node.getModifier();
523         if (node.isNot()) {
524             if ((modifierPattern & Modifier.PUBLIC) != 0) {
525                 if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
526                     return Boolean.TRUE;
527                 } else {
528                     return Boolean.FALSE;
529                 }
530             } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
531                 if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
532                     return Boolean.TRUE;
533                 } else {
534                     return Boolean.FALSE;
535                 }
536             } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
537                 if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
538                     return Boolean.TRUE;
539                 } else {
540                     return Boolean.FALSE;
541                 }
542             } else if ((modifierPattern & Modifier.STATIC) != 0) {
543                 if ((modifiersToMatch & Modifier.STATIC) == 0) {
544                     return Boolean.TRUE;
545                 } else {
546                     return Boolean.FALSE;
547                 }
548             } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
549                 if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
550                     return Boolean.TRUE;
551                 } else {
552                     return Boolean.FALSE;
553                 }
554             } else if ((modifierPattern & Modifier.FINAL) != 0) {
555                 if ((modifiersToMatch & Modifier.FINAL) == 0) {
556                     return Boolean.TRUE;
557                 } else {
558                     return Boolean.FALSE;
559                 }
560             } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
561                 if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
562                     return Boolean.TRUE;
563                 } else {
564                     return Boolean.FALSE;
565                 }
566             } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
567                 if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
568                     return Boolean.TRUE;
569                 } else {
570                     return Boolean.FALSE;
571                 }
572             } else if ((modifierPattern & Modifier.STRICT) != 0) {
573                 if ((modifiersToMatch & Modifier.STRICT) == 0) {
574                     return Boolean.TRUE;
575                 } else {
576                     return Boolean.FALSE;
577                 }
578             } else {
579                 return Boolean.FALSE;
580             }
581         } else {
582             if ((modifierPattern & Modifier.PUBLIC) != 0) {
583                 if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
584                     return Boolean.FALSE;
585                 } else {
586                     return Boolean.TRUE;
587                 }
588             } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
589                 if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
590                     return Boolean.FALSE;
591                 } else {
592                     return Boolean.TRUE;
593                 }
594             } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
595                 if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
596                     return Boolean.FALSE;
597                 } else {
598                     return Boolean.TRUE;
599                 }
600             } else if ((modifierPattern & Modifier.STATIC) != 0) {
601                 if ((modifiersToMatch & Modifier.STATIC) == 0) {
602                     return Boolean.FALSE;
603                 } else {
604                     return Boolean.TRUE;
605                 }
606             } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
607                 if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
608                     return Boolean.FALSE;
609                 } else {
610                     return Boolean.TRUE;
611                 }
612             } else if ((modifierPattern & Modifier.FINAL) != 0) {
613                 if ((modifiersToMatch & Modifier.FINAL) == 0) {
614                     return Boolean.FALSE;
615                 } else {
616                     return Boolean.TRUE;
617                 }
618             } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
619                 if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
620                     return Boolean.FALSE;
621                 } else {
622                     return Boolean.TRUE;
623                 }
624             } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
625                 if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
626                     return Boolean.FALSE;
627                 } else {
628                     return Boolean.TRUE;
629                 }
630             } else if ((modifierPattern & Modifier.STRICT) != 0) {
631                 if ((modifiersToMatch & Modifier.STRICT) == 0) {
632                     return Boolean.FALSE;
633                 } else {
634                     return Boolean.TRUE;
635                 }
636             } else {
637                 return Boolean.TRUE;
638             }
639         }
640     }
641 
642     protected boolean visitAttributes(SimpleNode node, ReflectionInfo refInfo) {
643         int nrChildren = node.jjtGetNumChildren();
644         if (nrChildren != 0) {
645             for (int i = 0; i < nrChildren; i++) {
646                 Node child = node.jjtGetChild(i);
647                 if (child instanceof ASTAttribute) {
648                     List annotations = refInfo.getAnnotations();
649                     if (Boolean.TRUE.equals(child.jjtAccept(this, annotations))) {
650                         continue;
651                     } else {
652                         return false;
653                     }
654                 }
655             }
656         }
657         return true;
658     }
659 
660     protected boolean visitModifiers(SimpleNode node, ReflectionInfo refInfo) {
661         int nrChildren = node.jjtGetNumChildren();
662         if (nrChildren != 0) {
663             for (int i = 0; i < nrChildren; i++) {
664                 Node child = node.jjtGetChild(i);
665                 if (child instanceof ASTModifier) {
666                     if (Boolean.TRUE.equals(child.jjtAccept(this, refInfo))) {
667                         continue;
668                     } else {
669                         return false;
670                     }
671                 }
672             }
673         }
674         return true;
675     }
676 
677     protected boolean visitParameters(SimpleNode node, ClassInfo[] parameterTypes) {
678         int nrChildren = node.jjtGetNumChildren();
679         if (nrChildren <= 0) {
680             return (parameterTypes.length==0);
681         }
682 
683         // collect the parameter nodes
684         List parameterNodes = new ArrayList();
685         for (int i = 0; i < nrChildren; i++) {
686             Node child = node.jjtGetChild(i);
687             if (child instanceof ASTParameter) {
688                 parameterNodes.add(child);
689             }
690         }
691 
692         if (parameterNodes.size() <= 0) {
693             return (parameterTypes.length==0);
694         }
695 
696         //TODO duplicate code with args() match
697         //TODO refactor parameterNodes in an array for faster match
698 
699         // look for eager pattern at the beginning and end
700         int expressionParameterCount = parameterNodes.size();
701         boolean isFirstArgEager = ((ASTParameter) parameterNodes.get(0)).getDeclaringClassPattern().isEagerWildCard();
702         boolean isLastArgEager = ((ASTParameter) parameterNodes.get(expressionParameterCount-1)).getDeclaringClassPattern().isEagerWildCard();
703         // foo(..)
704         if (isFirstArgEager && expressionParameterCount == 1) {
705             return true;
706         }
707         int contextParametersCount = parameterTypes.length;
708         if (isFirstArgEager && isLastArgEager) {
709             expressionParameterCount -= 2;
710             if (expressionParameterCount == 0) {
711                 // foo(.., ..)
712                 return true;
713             }
714             // we need to find a starting position - foo(..,int, bar, ..)
715             // foo(int) //int is ok
716             // foo(bar,int,bar) //int is ok
717             // foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
718             int matchCount = 0;
719             int ictx = 0;
720             for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
721                 if (ictx >= contextParametersCount) {
722                     // too many args in foo()
723                     matchCount = -1;
724                     break;
725                 }
726                 // do we have an eager wildcard in the middle ?
727                 ASTParameter parameterNode = (ASTParameter) parameterNodes.get(iexp+1);
728                 boolean isEager = parameterNode.getDeclaringClassPattern().isEagerWildCard();
729                 if (isEager) {
730                     // TODO - ignore for now, but not really supported - eager in the middle will match one
731                 }
732                 if (Boolean.TRUE.equals((Boolean) parameterNode.jjtAccept(this, parameterTypes[ictx]))) {
733                     matchCount += 1;
734                     ictx++;
735                 } else {
736                     // assume matched by starting ".." and rewind expression index
737                     matchCount = 0;
738                     ictx++;
739                     iexp = -1;
740                 }
741             }
742             if (matchCount == expressionParameterCount) {
743                 return true;
744             } else {
745                 return false;
746             }
747         } else if (isFirstArgEager) {
748             expressionParameterCount--;
749             if (contextParametersCount >= expressionParameterCount) {
750                 // do a match from last to first, break when foo() nodes are exhausted
751                 for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
752                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(expressionParameterCount - i);
753                     if (Boolean.TRUE.equals((Boolean) parameterNode.jjtAccept(
754                             this,
755                             parameterTypes[contextParametersCount -1 -i]))) {
756                         ;//go on with "next" param
757                     } else {
758                         return false;
759                     }
760                 }
761                 return true;
762             } else {
763                 //foo() as more param than context we try to match
764                 return false;
765             }
766         } else if (isLastArgEager) {
767             expressionParameterCount--;
768             if (contextParametersCount >= expressionParameterCount) {
769                 // do a match from first to last, break when foo() nodes are exhausted
770                 for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
771                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
772                     if (Boolean.TRUE.equals((Boolean) parameterNode.jjtAccept(this, parameterTypes[i]))) {
773                         ;//go on with next param
774                     } else {
775                         return false;
776                     }
777                 }
778                 return true;
779             } else {
780                 return false;
781             }
782         } else {
783             // no eager wildcard in foo()
784             // check that param length are equals
785             if (expressionParameterCount == contextParametersCount) {
786                 for (int i = 0; i < parameterNodes.size(); i++) {
787                     ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
788                     if (Boolean.TRUE.equals((Boolean) parameterNode.jjtAccept(this, parameterTypes[i]))) {
789                         ;//go on with next param
790                     } else {
791                         return false;
792                     }
793                 }
794                 return true;
795             } else {
796                 return false;
797             }
798         }
799     }
800 
801     /***
802      * Returns the string representation of the expression.
803      * 
804      * @return
805      */
806     public String toString() {
807         return m_expression;
808     }
809 
810     /***
811      * Returns the number of parameters to the target method/constructor else -1.
812      *
813      * @param ctx
814      * @return
815      */
816     private int getParametersCount(final ExpressionContext ctx) {
817         ReflectionInfo reflectionInfo = ctx.getReflectionInfo();
818         if (reflectionInfo instanceof MethodInfo) {
819             return ((MethodInfo) reflectionInfo).getParameterTypes().length;
820         } else if (reflectionInfo instanceof ConstructorInfo) {
821             return ((ConstructorInfo) reflectionInfo).getParameterTypes().length;
822         } else if (reflectionInfo instanceof FieldInfo) {
823             return 1;//field set support for args()
824         } else {
825             return -1;
826         }
827     }
828 }