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.expression.ast.ASTAnd;
    11  import org.codehaus.aspectwerkz.expression.ast.ASTAttribute;
    12  import org.codehaus.aspectwerkz.expression.ast.ASTCall;
    13  import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
    14  import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
    15  import org.codehaus.aspectwerkz.expression.ast.ASTClassPattern;
    16  import org.codehaus.aspectwerkz.expression.ast.ASTConstructorPattern;
    17  import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
    18  import org.codehaus.aspectwerkz.expression.ast.ASTExpression;
    19  import org.codehaus.aspectwerkz.expression.ast.ASTFieldPattern;
    20  import org.codehaus.aspectwerkz.expression.ast.ASTGet;
    21  import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
    22  import org.codehaus.aspectwerkz.expression.ast.ASTMethodPattern;
    23  import org.codehaus.aspectwerkz.expression.ast.ASTModifier;
    24  import org.codehaus.aspectwerkz.expression.ast.ASTParameter;
    25  import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
    26  import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
    27  import org.codehaus.aspectwerkz.expression.ast.ASTSet;
    28  import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
    29  import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
    30  import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
    31  import org.codehaus.aspectwerkz.expression.ast.ExpressionParserVisitor;
    32  import org.codehaus.aspectwerkz.expression.ast.Node;
    33  import org.codehaus.aspectwerkz.expression.ast.SimpleNode;
    34  import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
    35  import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
    36  import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
    37  import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
    38  import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
    39  import org.codehaus.aspectwerkz.expression.ast.ASTThis;
    40  import org.codehaus.aspectwerkz.expression.ast.ASTNot;
    41  import org.codehaus.aspectwerkz.expression.regexp.TypePattern;
    42  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    43  import org.codehaus.aspectwerkz.reflect.MemberInfo;
    44  import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
    45  import org.codehaus.aspectwerkz.reflect.MethodInfo;
    46  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
    47  import org.codehaus.aspectwerkz.reflect.FieldInfo;
    48  import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
    49  import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
    50  import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
    51  import org.codehaus.aspectwerkz.util.Util;
    52
    53  import java.util.List;
    54  import java.util.Iterator;
    55
    56  /***
    57   * The advised class filter visitor.
    58   * <p/>
    59   * Visit() methods are returning Boolean.TRUE/FALSE or null when decision cannot be taken.
    60   * Using null allow composition of OR/AND with NOT in the best way.
    61   *
    62   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    63   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    64   * @author Michael Nascimento
    65   * @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
    66   */
    67  public class AdvisedClassFilterExpressionVisitor extends ExpressionVisitor implements ExpressionParserVisitor {
    68
    69      /***
    70       * Creates a new expression.
    71       *
    72       * @param expression the expression as a string
    73       * @param namespace  the namespace
    74       * @param root       the AST root
    75       */
    76      public AdvisedClassFilterExpressionVisitor(final ExpressionInfo expressionInfo, final String expression,
    77                                                 final String namespace, final Node root) {
    78          super(expressionInfo, expression, namespace, root);
    79      }
    80
    81      // ============ Boot strap =============
    82      public Object visit(SimpleNode node, Object data) {
    83          return node.jjtGetChild(0).jjtAccept(this, data);
    84      }
    85
    86      public Object visit(ASTRoot node, Object data) {
    87          Node child = node.jjtGetChild(0);
    88          Boolean match = (Boolean) child.jjtAccept(this, data);
    89          return match;
    90      }
    91
    92      public Object visit(ASTExpression node, Object data) {
    93          Node child = node.jjtGetChild(0);
    94          Boolean match = (Boolean) child.jjtAccept(this, data);
    95          return match;
    96      }
    97
    98      public Object visit(ASTNot node, Object data) {
    99          return super.visit(node,data);
    100     }
    101
    102     // ============ Pointcut types =============
    103     public Object visit(ASTPointcutReference node, Object data) {
    104         ExpressionContext context = (ExpressionContext) data;
    105         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
    106         AdvisedClassFilterExpressionVisitor expression = namespace.getAdvisedClassExpression(node.getName());
    107         return expression.matchUndeterministic(context);
    108     }
    109
    110     public Object visit(ASTExecution node, Object data) {
    111         ExpressionContext context = (ExpressionContext) data;
    112
    113         // only the last node might be the pattern, others are annotations
    114         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    115         boolean checkPattern = !(patternNode instanceof ASTAttribute);
    116
    117         if(checkPattern) {
    118             if (context.hasWithinPointcut() || context.hasExecutionPointcut()) {
    119                 if (context.hasExecutionPointcut()) {
    120                     // reflectionInfo was given
    121                     return patternNode.jjtAccept(this, context.getReflectionInfo());
    122                 } else {
    123                     // only withinInfo was given
    124                     return patternNode.jjtAccept(this, context.getWithinReflectionInfo());
    125                 }
    126             } else {
    127                 return Boolean.FALSE;
    128             }
    129         } else {
    130         	return null;
    131         }
    132     }
    133
    134     public Object visit(ASTCall node, Object data) {
    135         ExpressionContext context = (ExpressionContext) data;
    136
    137         // only the last node might be the pattern, others are annotations
    138         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    139         boolean checkPattern = !(patternNode instanceof ASTAttribute);
    140
    141         if(checkPattern) {
    142             if (context.hasWithinPointcut() || context.hasCallPointcut()) {
    143                 if (context.hasReflectionInfo()) {
    144                         return patternNode.jjtAccept(this, context.getReflectionInfo());
    145                 } else {
    146                     return null;
    147                 }
    148             } else {
    149                 return Boolean.FALSE;
    150             }
    151         } else {
    152         	return null;
    153         }
    154     }
    155
    156     public Object visit(ASTSet node, Object data) {
    157         ExpressionContext context = (ExpressionContext) data;
    158
    159         // only the last node might be the pattern, others are annotations
    160         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    161         boolean checkPattern = !(patternNode instanceof ASTAttribute);
    162
    163         // for set evaluation, the reflection info may be null at the early matching phase
    164         // when we will allow for field interception within non declaring class
    165         if(checkPattern) {
    166             if (context.hasWithinPointcut() || context.hasSetPointcut()) {
    167                 if (context.hasReflectionInfo()) {
    168                         return patternNode.jjtAccept(this, context.getReflectionInfo());
    169                 } else {
    170                     return null;
    171                 }
    172             } else {
    173                 return Boolean.FALSE;
    174             }
    175         } else {
    176         	return null;
    177         }
    178     }
    179
    180     public Object visit(ASTGet node, Object data) {
    181         ExpressionContext context = (ExpressionContext) data;
    182
    183         // only the last node might be the pattern, others are annotations
    184         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    185         boolean checkPattern = !(patternNode instanceof ASTAttribute);
    186
    187         // for get evaluation, the reflection info may be null at the early matching phase
    188         // since we allow for field interception within non declaring class
    189         if(checkPattern) {
    190             if (context.hasWithinPointcut() || context.hasGetPointcut()) {
    191                 if (context.hasReflectionInfo()) {
    192                 	return patternNode.jjtAccept(this, context.getReflectionInfo());
    193                 } else {
    194                     return null;
    195                 }
    196             } else {
    197                 return Boolean.FALSE;
    198             }
    199         } else {
    200         	return null;
    201         }
    202     }
    203
    204     public Object visit(ASTHandler node, Object data) {
    205         return null;
    206     }
    207
    208     public Object visit(ASTStaticInitialization node, Object data) {
    209         ExpressionContext context = (ExpressionContext) data;
    210
    211         if (context.hasStaticInitializationPointcut() && context.hasWithinReflectionInfo()) {
    212         	ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
    213             if (reflectInfo instanceof StaticInitializationInfo) {
    214                 reflectInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
    215             }
    216         	if (reflectInfo instanceof ClassInfo) {
    217                 // In an annotated subtree, the last child node represents the pattern
    218                 Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    219                 if (!(patternNode instanceof ASTAttribute)) {
    220                     Boolean matchPattern = (Boolean) patternNode.jjtAccept(this, reflectInfo);
    221                     if (Boolean.FALSE.equals(matchPattern)) {
    222                         return Boolean.FALSE;
    223                     }
    224                 }
    225
    226                 // match on the annotations since the pattern was not there or matched
    227             	boolean matchedAnnotations = visitAttributes(node, reflectInfo);
    228             	if (!matchedAnnotations) {
    229             		return Boolean.FALSE;
    230             	} else {
    231                     return null;//match but early phase
    232                 }
    233         	} else {
    234         		return Boolean.FALSE;
    235         	}
    236         } else {
    237             return Boolean.FALSE;
    238         }
    239     }
    240
    241     public Object visit(ASTWithinCode node, Object data) {
    242         ExpressionContext context = (ExpressionContext) data;
    243         ReflectionInfo withinInfo = context.getWithinReflectionInfo();
    244
    245         if (node.isStaticInitializer()) {
    246             // transform the node in a within node to do an exact match on the within info
    247             //TODO would be worth to do the fastNode creation only once somewhere
    248             ASTWithin fastNode = new ASTWithin(0);
    249             for (int i = 0; i < node.jjtGetChild(0).jjtGetNumChildren(); i++) {
    250                   fastNode.jjtAddChild(node.jjtGetChild(0).jjtGetChild(i), i);
    251             }
    252             return super.visit(fastNode, data);
    253         } else {
    254 	        Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
    255 	        boolean checkPattern = !(patternNode instanceof ASTAttribute);
    256
    257 	        if (checkPattern) {
    258 	            if (withinInfo instanceof MemberInfo) {
    259 	                return patternNode.jjtAccept(this, withinInfo);
    260 	            } else if (withinInfo instanceof ClassInfo) {
    261 	                Boolean matchDeclaringType = (Boolean) patternNode.jjtAccept(this, withinInfo);
    262 	                if (Boolean.FALSE.equals(matchDeclaringType)) {
    263 	                    return Boolean.FALSE;
    264 	                } else {
    265 	                    // may be we match now but not later?
    266 	                    return null;
    267 	                }
    268 	            } else {
    269 	                return null;
    270 	            }
    271 	        } else {
    272 	            return null;
    273 	        }
    274         }
    275     }
    276
    277     public Object visit(ASTCflow node, Object data) {
    278         return null;
    279     }
    280
    281     public Object visit(ASTCflowBelow node, Object data) {
    282         return null;
    283     }
    284
    285     public Object visit(ASTArgs node, Object data) {
    286         return null;
    287     }
    288
    289     public Object visit(ASTTarget node, Object data) {
    290         return null;// is that good enough ? For execution PC we would optimize some
    291     }
    292
    293     public Object visit(ASTThis node, Object data) {
    294         ExpressionContext context = (ExpressionContext) data;
    295         if (context.hasWithinReflectionInfo()) {
    296             ReflectionInfo withinInfo = context.getWithinReflectionInfo();
    297             if (withinInfo instanceof MemberInfo) {
    298                 return Util.booleanValueOf(
    299                         ClassInfoHelper.instanceOf(
    300                                 ((MemberInfo) withinInfo).getDeclaringType(),
    301                                 node.getBoundedType(m_expressionInfo)
    302                         )
    303                 );
    304             } else if (withinInfo instanceof ClassInfo) {
    305                 return Util.booleanValueOf(
    306                         ClassInfoHelper.instanceOf((ClassInfo) withinInfo, node.getBoundedType(m_expressionInfo))
    307                 );
    308             }
    309         }
    310         return Boolean.FALSE;
    311     }
    312
    313     // ============ Patterns =============
    314 //    public Object visit(ASTClassPattern node, Object data) {
    315 //        if(null == data) {
    316 //            return null;
    317 //        } else if( !(data instanceof ClassInfo) ) {
    318 //        	return Boolean.FALSE;
    319 //        }
    320 //
    321 //        ClassInfo classInfo = (ClassInfo) data;
    322 //        if (node.getTypePattern().matchType(classInfo) && visitAttributes(node, classInfo)) {
    323 //            return Boolean.TRUE;
    324 //        } else {
    325 //            return Boolean.FALSE;
    326 //        }
    327 //    }
    328
    329     public Object visit(ASTMethodPattern node, Object data) {
    330         if (data instanceof ClassInfo) {
    331             ClassInfo classInfo = (ClassInfo) data;
    332             if (node.getDeclaringTypePattern().matchType(classInfo)) {
    333                 return Boolean.TRUE;
    334             }
    335             return Boolean.FALSE;
    336         } else if (data instanceof MethodInfo) {
    337             MethodInfo methodInfo = (MethodInfo) data;
    338             if (node.getDeclaringTypePattern().matchType(methodInfo.getDeclaringType())) {
    339                 return null;// it might not match further because of modifiers etc
    340             }
    341             return Boolean.FALSE;
    342         }
    343         return Boolean.FALSE;
    344     }
    345
    346     public Object visit(ASTConstructorPattern node, Object data) {
    347         if (data instanceof ClassInfo) {
    348             ClassInfo classInfo = (ClassInfo) data;
    349             if (node.getDeclaringTypePattern().matchType(classInfo)) {
    350                 // we matched but the actual match result may be false
    351                 return Boolean.TRUE;
    352             }
    353         } else if (data instanceof ConstructorInfo) {
    354             ConstructorInfo constructorInfo = (ConstructorInfo) data;
    355             if (node.getDeclaringTypePattern().matchType(constructorInfo.getDeclaringType())) {
    356                 return null;// it might not match further because of modifiers etc
    357             }
    358             return Boolean.FALSE;
    359         }
    360         return Boolean.FALSE;
    361     }
    362
    363     public Object visit(ASTFieldPattern node, Object data) {
    364         if (data instanceof ClassInfo) {
    365             ClassInfo classInfo = (ClassInfo) data;
    366             if (node.getDeclaringTypePattern().matchType(classInfo)) {
    367                 // we matched but the actual match result may be false
    368                 return Boolean.TRUE;
    369             }
    370         } else if (data instanceof FieldInfo) {
    371             FieldInfo fieldInfo = (FieldInfo) data;
    372             if (node.getDeclaringTypePattern().matchType(fieldInfo.getDeclaringType())) {
    373                 return null;// it might not match further because of modifiers etc
    374             }
    375             return Boolean.FALSE;
    376         }
    377         return Boolean.FALSE;
    378     }
    379
    380     public Object visit(ASTParameter node, Object data) {
    381         ClassInfo parameterType = (ClassInfo) data;
    382         if (node.getDeclaringClassPattern().matchType(parameterType)) {
    383             // we matched but the actual match result may be false
    384             return Boolean.TRUE;
    385         } else {
    386             return Boolean.FALSE;
    387         }
    388     }
    389
    390     public Object visit(ASTArgParameter node, Object data) {
    391         // never called
    392         return Boolean.TRUE;
    393     }
    394
    395     public Object visit(ASTAttribute node, Object data) {
    396         // called for class level annotation matching f.e. in a within context
    397         boolean matchAnnotation = false;
    398         List annotations = (List) data;
    399         for (Iterator it = annotations.iterator(); it.hasNext();) {
    400             AnnotationInfo annotation = (AnnotationInfo) it.next();
    401             if (annotation.getName().equals(node.getName())) {
    402                 matchAnnotation = true;
    403             }
    404         }
    405         if (node.isNot()) {
    406             return Util.booleanValueOf(!matchAnnotation);
    407         } else {
    408             return Util.booleanValueOf(matchAnnotation);
    409         }
    410     }
    411
    412     public Object visit(ASTModifier node, Object data) {
    413         // TODO
    414         return null;
    415     }
    416
    417     /***
    418      * Returns the string representation of the AST.
    419      *
    420      * @return
    421      */
    422     public String toString() {
    423         return m_expression;
    424     }
    425 }