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.ASTRoot;
11  import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
12  import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
13  import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
14  import org.codehaus.aspectwerkz.util.Strings;
15  import org.codehaus.aspectwerkz.exception.DefinitionException;
16  
17  import java.util.Iterator;
18  
19  import gnu.trove.TIntIntHashMap;
20  
21  /***
22   * A visitor to compute the args index of the target (matching) method/constructor which match the advice args. Note:
23   * extends the ExpressionVisitor. We should allow for optimization (all=TRUE) by assuming that args(..) does not depends
24   * of the matching context. The "(String a, String b):methodX && args(a,b) -OR- methodY && args(b,a)" expression should
25   * not be allowed then. TODO check support for anonymous pc
26   * 
27   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
28   */
29  public class ArgsIndexVisitor extends ExpressionVisitor {
30  
31      public ArgsIndexVisitor(final ExpressionInfo expressionInfo,
32                              final String expression,
33                              final String namespace,
34                              final ASTRoot root) {
35          super(expressionInfo, expression, namespace, root);
36      }
37  
38      //-- overrided methods to compute the args index mapping --//
39  
40      public Object visit(ASTPointcutReference node, Object data) {
41          // do the sub expression visit
42          ExpressionContext context = (ExpressionContext) data;
43          ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
44          ArgsIndexVisitor expression = namespace.getExpressionInfo(node.getName()).getArgsIndexMapper();
45          if (expression == null) {
46              throw new DefinitionException("Could not find pointcut reference " + node.getName() +
47                      " in namespace " + m_namespace);
48          }
49          Boolean match = new Boolean(expression.match(context));
50  
51          // update the context mapping from this last visit
52          // did we visit some args(<name>) nodes ?
53          if (!context.m_exprIndexToTargetIndex.isEmpty()) {
54              TIntIntHashMap sourceToTargetArgIndexes = new TIntIntHashMap();
55              int index = 0;
56              for (Iterator it = m_expressionInfo.getArgumentNames().iterator(); it.hasNext(); index++) {
57                  String adviceParamName = (String) it.next();
58                  //look for adviceParamName in the expression name and get its index
59                  int exprArgIndex = ArgsIndexVisitor.getExprArgIndex(m_expression, adviceParamName);
60                  if (exprArgIndex < 0) {
61                      //param of advice not found in pc signature - f.e. "joinPoint"
62                      continue;
63                  }
64                  int adviceArgIndex = m_expressionInfo.getArgumentIndex(adviceParamName);
65                  int targetArgIndex = context.m_exprIndexToTargetIndex.get(exprArgIndex);
66                  //                System.out.println(" transitive arg" + adviceArgIndex + " " + adviceParamName + " -> " + exprArgIndex
67                  // + " -> " + targetArgIndex);
68                  sourceToTargetArgIndexes.put(adviceArgIndex, targetArgIndex);
69              }
70              context.m_exprIndexToTargetIndex = sourceToTargetArgIndexes;
71  
72              //debug:
73              //            if (m_expressionInfo.m_isAdviceBindingWithArgs) {
74              //                System.out.println("XXXARGS transitive map for an advice is @ " +
75              //                        m_expression + " for " + context.getReflectionInfo().getName());
76              //                for (int i = 0; i < sourceToTargetArgIndexes.keys().length; i++) {
77              //                    int adviceArgIndex = sourceToTargetArgIndexes.keys()[i];
78              //                    int targetMethodIndex = sourceToTargetArgIndexes.get(adviceArgIndex);
79              //                    System.out.println(" " + adviceArgIndex + " - " + targetMethodIndex);
80              //                }
81              //            }
82          }
83          return match;
84      }
85  
86      public Object visit(ASTArgs node, Object data) {
87          return super.visit(node, data);
88      }
89  
90      public Object visit(ASTArgParameter node, Object data) {
91          // do the visit
92          Boolean match = (Boolean) super.visit(node, data);
93  
94          // get the pointcut signature arg index of the arg we are visiting
95          int pointcutArgIndex = -1;
96          if (node.getTypePattern().getPattern().indexOf(".") < 0) {
97              pointcutArgIndex = m_expressionInfo.getArgumentIndex(node.getTypePattern().getPattern());
98          }
99  
100         // if match and we are visiting a parameter binding (not a type matching)
101         if (pointcutArgIndex >= 0 && Boolean.TRUE.equals(match)) {
102             ExpressionContext ctx = (ExpressionContext) data;
103 //                        System.out.println("XXXARGS targetArg at match: " + ctx.getCurrentTargetArgsIndex() + " is pc expr arg "
104 //             + pointcutArgIndex
105 //                            + " @ " + m_expressionInfo.getExpressionAsString());
106             ctx.m_exprIndexToTargetIndex.put(pointcutArgIndex, ctx.getCurrentTargetArgsIndex());
107         }
108         return match;
109     }
110 
111     /***
112      * Get the parameter index from a "call side" like signature like pc(a, b) => index(a) = 0, or -1 if not found
113      * 
114      * @param expression
115      * @param adviceParamName
116      * @return
117      */
118     private static int getExprArgIndex(String expression, String adviceParamName) {
119         //TODO - support for anonymous pointcut with args
120         int paren = expression.indexOf('(');
121         if (paren > 0) {
122             String params = expression.substring(paren + 1, expression.lastIndexOf(')')).trim();
123             String[] parameters = Strings.splitString(params, ",");
124             int paramIndex = 0;
125             for (int i = 0; i < parameters.length; i++) {
126                 String parameter = parameters[i].trim();
127                 if (parameter.length() > 0) {
128                     if (adviceParamName.equals(parameter)) {
129                         return paramIndex;
130                     } else {
131                         paramIndex++;
132                     }
133                 }
134             }
135         }
136         return -1;
137     }
138 
139 }