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 }