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.joinpoint.management;
9   
10  import org.codehaus.aspectwerkz.AspectSystem;
11  import org.codehaus.aspectwerkz.AdviceInfo;
12  import org.codehaus.aspectwerkz.util.Strings;
13  import org.codehaus.aspectwerkz.aspect.management.AspectManager;
14  import org.codehaus.aspectwerkz.aspect.management.Pointcut;
15  import org.codehaus.aspectwerkz.expression.ExpressionContext;
16  import org.codehaus.aspectwerkz.expression.PointcutType;
17  import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
18  
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  /***
24   * Holds and creates meta data about a specific join point.
25   *
26   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
27   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
28   */
29  public class JoinPointMetaData {
30      /***
31       * The indexes for the advices.
32       */
33      public AdviceIndexInfo[] adviceIndexes;
34  
35      /***
36       * The cflow expressions runtime.
37       */
38      public List cflowExpressions;
39  
40      /***
41       * The cflow pointcut.
42       */
43      public Pointcut cflowPointcut;
44  
45      /***
46       * The join point expression context
47       */
48      public ExpressionContext expressionContext;
49  
50      /***
51       * Retrieves the join point metadata.
52       *
53       * @param type
54       * @param system
55       * @param reflectInfo
56       * @param withinInfo
57       */
58      public static JoinPointMetaData getJoinPointMetaData(final PointcutType type,
59                                                           final AspectSystem system,
60                                                           final ReflectionInfo reflectInfo,
61                                                           final ReflectionInfo withinInfo) {
62  
63          List adviceIndexInfoList = new ArrayList();
64          List cflowExpressionList = new ArrayList();
65          Pointcut cflowPointcut = null;
66  
67          ExpressionContext ctx = new ExpressionContext(type, reflectInfo, withinInfo);//AVAJ null?
68          AspectManager[] aspectManagers = system.getAspectManagers();
69          for (int i = 0; i < aspectManagers.length; i++) {
70              AspectManager aspectManager = aspectManagers[i];
71  
72              /// grab the first one found, one single cflow pointcut is enough per join point
73              if (cflowPointcut == null) {
74                  List cflowPointcuts = aspectManager.getCflowPointcuts(ctx);
75                  if (!cflowPointcuts.isEmpty()) {
76                      cflowPointcut = (Pointcut) cflowPointcuts.get(0);
77                  }
78              }
79  
80              // get all matching pointcuts from all managers
81              for (Iterator it = aspectManager.getPointcuts(ctx).iterator(); it.hasNext();) {
82                  Pointcut pointcut = (Pointcut) it.next();
83  
84                  AdviceInfo[] aroundAdviceIndexes = pointcut.getAroundAdviceIndexes();
85                  AdviceInfo[] beforeAdviceIndexes = pointcut.getBeforeAdviceIndexes();
86                  AdviceInfo[] afterFinallyAdviceIndexes = pointcut.getAfterFinallyAdviceIndexes();
87                  AdviceInfo[] afterReturningAdviceIndexes = pointcut.getAfterReturningAdviceIndexes();
88                  AdviceInfo[] afterThrowingAdviceIndexes = pointcut.getAfterThrowingAdviceIndexes();
89  
90                  AdviceIndexInfo adviceIndexInfo = new AdviceIndexInfo(
91                          aroundAdviceIndexes,
92                          beforeAdviceIndexes,
93                          afterFinallyAdviceIndexes,
94                          afterReturningAdviceIndexes,
95                          afterThrowingAdviceIndexes
96                  );
97  
98                  // compute target args to advice args mapping, it is a property of each *advice*
99  
100                 // refresh the arg index map
101                 pointcut.getExpressionInfo().getArgsIndexMapper().match(ctx);
102 
103                 //TODO can we do cache, can we do in another visitor
104                 //TODO skip map when no args()
105 
106                 for (int j = 0; j < aroundAdviceIndexes.length; j++) {
107                     setMethodArgumentIndexes(pointcut.getAroundAdviceName(j), pointcut, ctx, aroundAdviceIndexes[j]);
108                 }
109 
110                 for (int j = 0; j < beforeAdviceIndexes.length; j++) {
111                     setMethodArgumentIndexes(pointcut.getBeforeAdviceName(j), pointcut, ctx, beforeAdviceIndexes[j]);
112                 }
113 
114                 for (int j = 0; j < afterFinallyAdviceIndexes.length; j++) {
115                     setMethodArgumentIndexes(
116                             pointcut.getAfterFinallyAdviceName(j), pointcut, ctx, afterFinallyAdviceIndexes[j]
117                     );
118                 }
119 
120                 for (int j = 0; j < afterReturningAdviceIndexes.length; j++) {
121                     setMethodArgumentIndexes(
122                             pointcut.getAfterReturningAdviceName(j), pointcut, ctx, afterReturningAdviceIndexes[j]
123                     );
124                 }
125 
126                 for (int j = 0; j < afterThrowingAdviceIndexes.length; j++) {
127                     setMethodArgumentIndexes(
128                             pointcut.getAfterThrowingAdviceName(j), pointcut, ctx, afterThrowingAdviceIndexes[j]
129                     );
130 
131                 }
132 
133                 adviceIndexInfoList.add(adviceIndexInfo);
134 
135                 // collect the cflow expressions for the matching pointcuts (if they have one)
136                 if (pointcut.getExpressionInfo().hasCflowPointcut()) {
137                     cflowExpressionList.add(pointcut.getExpressionInfo().getCflowExpressionRuntime());
138                 }
139             }
140         }
141 
142         // turn the lists into arrays for performance reasons
143         AdviceIndexInfo[] adviceIndexInfo = new AdviceIndexInfo[adviceIndexInfoList.size()];
144         int i = 0;
145         for (Iterator iterator = adviceIndexInfoList.iterator(); iterator.hasNext(); i++) {
146             adviceIndexInfo[i] = (AdviceIndexInfo) iterator.next();
147         }
148         JoinPointMetaData metaData = new JoinPointMetaData();
149         metaData.adviceIndexes = adviceIndexInfo;
150         metaData.cflowExpressions = cflowExpressionList;
151         metaData.cflowPointcut = cflowPointcut;
152         metaData.expressionContext = ctx;
153         return metaData;
154     }
155 
156     /***
157      * Get the parameter names from a "method declaration" signature like pc(type a, type2 b) => 0:a, 1:b
158      *
159      * @param expression
160      * @return the parameter names
161      */
162     public static String[] getParameterNames(final String expression) {
163         int paren = expression.indexOf('(');
164         List paramNames = new ArrayList();
165         if (paren > 0) {
166             String params = expression.substring(paren + 1, expression.lastIndexOf(')')).trim();
167             String[] javaParameters = Strings.splitString(params, ",");
168             for (int i = 0; i < javaParameters.length; i++) {
169                 String javaParameter = Strings.replaceSubString(javaParameters[i], "  ", " ").trim();
170                 String[] paramInfo = Strings.splitString(javaParameter, " ");
171                 paramNames.add(paramInfo[1]);
172             }
173         }
174         String[] paramNamesArray = new String[paramNames.size()];
175         int index = 0;
176         for (Iterator it = paramNames.iterator(); it.hasNext(); index++) {
177             paramNamesArray[index] = (String) it.next();
178         }
179         return paramNamesArray;
180     }
181 
182     /***
183      * Sets the method argument indexes.
184      * 
185      * @param adviceName
186      * @param pointcut
187      * @param ctx
188      * @param indexTuple
189      */
190     private static void setMethodArgumentIndexes(final String adviceName,
191                                                  final Pointcut pointcut,
192                                                  final ExpressionContext ctx,
193                                                  final AdviceInfo indexTuple) {
194         //grab the parameters names
195         String[] adviceArgNames = JoinPointMetaData.getParameterNames(adviceName);
196 
197         // map them from the ctx info
198         int[] adviceToTargetArgs = new int[adviceArgNames.length];
199         for (int k = 0; k < adviceArgNames.length; k++) {
200             String adviceArgName = adviceArgNames[k];
201             int exprArgIndex = pointcut.getExpressionInfo().getArgumentIndex(adviceArgName);
202             if (exprArgIndex >= 0 && ctx.m_exprIndexToTargetIndex.containsKey(exprArgIndex)) {
203                 adviceToTargetArgs[k] = ctx.m_exprIndexToTargetIndex.get(exprArgIndex);
204             } else {
205                 adviceToTargetArgs[k] = -1;
206             }
207         }
208         indexTuple.setMethodToArgIndexes(adviceToTargetArgs);
209     }
210 
211 }