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 gnu.trove.TLongObjectHashMap;
11  import org.codehaus.aspectwerkz.AspectSystem;
12  import org.codehaus.aspectwerkz.AdviceInfo;
13  import org.codehaus.aspectwerkz.aspect.management.AspectManager;
14  import org.codehaus.aspectwerkz.aspect.management.AspectRegistry;
15  import org.codehaus.aspectwerkz.aspect.management.Pointcut;
16  import org.codehaus.aspectwerkz.expression.ExpressionContext;
17  import org.codehaus.aspectwerkz.expression.PointcutType;
18  import org.codehaus.aspectwerkz.reflect.ClassInfo;
19  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
20  import org.codehaus.aspectwerkz.reflect.FieldInfo;
21  import org.codehaus.aspectwerkz.reflect.MethodInfo;
22  import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
23  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
24  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfoRepository;
25  import org.codehaus.aspectwerkz.reflect.impl.java.JavaConstructorInfo;
26  import org.codehaus.aspectwerkz.reflect.impl.java.JavaFieldInfo;
27  import org.codehaus.aspectwerkz.reflect.impl.java.JavaMethodInfo;
28  
29  import java.lang.reflect.Constructor;
30  import java.lang.reflect.Method;
31  import java.util.ArrayList;
32  import java.util.HashMap;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Map;
36  
37  /***
38   * Manages the registration of join points and advices for these join points.
39   *
40   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
41   */
42  public class JoinPointRegistry {
43      /***
44       * Pre allocated empty array list.
45       */
46      private static final List EMTPY_ARRAY_LIST = new ArrayList();
47  
48      /***
49       * The registry with all the classes and the index for the advices attatched to the join points in this class.
50       * <p/>Map of: the class hash => map of: join point hash => map of: join point type => array with advice indexes.
51       */
52      private static final TLongObjectHashMap m_joinPointMetaDataMap = new TLongObjectHashMap();
53  
54      /***
55       * The registry with all the classes and the index for the cflow expressions attatched to the join points in this
56       * class. <p/>Map of: the class hash => map of: join point hash => map of: join point type => array cflow
57       * expressions.
58       */
59      private static final TLongObjectHashMap m_joinPointCflowExpressionMap = new TLongObjectHashMap();
60  
61      /***
62       * Registers the advices for the method join point.
63       *
64       * @param joinPointType
65       * @param joinPointHash
66       * @param signature
67       * @param classHash
68       * @param declaringClass
69       * @param withinInfo
70       * @param system
71       * @TODO: cache the metadata created in the method - map it to the method hash (see pointcut for caching)
72       */
73      public void registerJoinPoint(final int joinPointType,
74                                    final int joinPointHash,
75                                    final String signature,
76                                    final int classHash,
77                                    final Class declaringClass,
78                                    final ReflectionInfo withinInfo,
79                                    final AspectSystem system) {
80          if (!m_joinPointMetaDataMap.containsKey(classHash)) {
81              m_joinPointMetaDataMap.put(classHash, new TLongObjectHashMap());
82          }
83          Map joinPointMetaDataMap = new HashMap();
84          joinPointMetaDataMap.put(PointcutType.EXECUTION, EMTPY_ARRAY_LIST);
85          joinPointMetaDataMap.put(PointcutType.CALL, EMTPY_ARRAY_LIST);
86          joinPointMetaDataMap.put(PointcutType.SET, EMTPY_ARRAY_LIST);
87          joinPointMetaDataMap.put(PointcutType.GET, EMTPY_ARRAY_LIST);
88          joinPointMetaDataMap.put(PointcutType.HANDLER, EMTPY_ARRAY_LIST);
89          joinPointMetaDataMap.put(PointcutType.STATIC_INITIALIZATION, EMTPY_ARRAY_LIST);
90  //        joinPointMetaDataMap.put(PointcutType.ATTRIBUTE, EMTPY_ARRAY_LIST);
91          ((TLongObjectHashMap) m_joinPointMetaDataMap.get(classHash)).put(joinPointHash, joinPointMetaDataMap);
92          switch (joinPointType) {
93              case JoinPointType.METHOD_EXECUTION:
94                  Method wrapperMethod = AspectRegistry.getMethodTuple(declaringClass, joinPointHash).getWrapperMethod();
95                  MethodInfo methodInfo = JavaMethodInfo.getMethodInfo(wrapperMethod);
96                  registerJoinPoint(
97                          PointcutType.EXECUTION, system, methodInfo, methodInfo/*AVAJ*/, joinPointMetaDataMap
98                  );
99                  break;
100             case JoinPointType.METHOD_CALL:
101                 wrapperMethod = AspectRegistry.getMethodTuple(declaringClass, joinPointHash).getWrapperMethod();
102                 methodInfo = JavaMethodInfo.getMethodInfo(wrapperMethod);
103                 registerJoinPoint(PointcutType.CALL, system, methodInfo, withinInfo, joinPointMetaDataMap);
104                 break;
105             case JoinPointType.CONSTRUCTOR_EXECUTION:
106                 Constructor wrapperConstructor = AspectRegistry.getConstructorTuple(declaringClass, joinPointHash)
107                         .getWrapperConstructor();
108                 ConstructorInfo constructorInfo = JavaConstructorInfo.getConstructorInfo(wrapperConstructor);
109                 registerJoinPoint(
110                         PointcutType.EXECUTION, system, constructorInfo, constructorInfo/*AVAJ*/, joinPointMetaDataMap
111                 );
112                 break;
113             case JoinPointType.CONSTRUCTOR_CALL:
114                 wrapperConstructor = AspectRegistry.getConstructorTuple(declaringClass, joinPointHash)
115                         .getWrapperConstructor();
116                 constructorInfo = JavaConstructorInfo.getConstructorInfo(wrapperConstructor);
117                 registerJoinPoint(PointcutType.CALL, system, constructorInfo, withinInfo, joinPointMetaDataMap);
118                 break;
119             case JoinPointType.FIELD_SET:
120                 FieldInfo fieldInfo = JavaFieldInfo
121                         .getFieldInfo(AspectRegistry.getField(declaringClass, joinPointHash));
122                 registerJoinPoint(PointcutType.SET, system, fieldInfo, withinInfo, joinPointMetaDataMap);
123                 break;
124             case JoinPointType.FIELD_GET:
125                 fieldInfo = JavaFieldInfo.getFieldInfo(AspectRegistry.getField(declaringClass, joinPointHash));
126                 registerJoinPoint(PointcutType.GET, system, fieldInfo, withinInfo, joinPointMetaDataMap);
127                 break;
128             case JoinPointType.HANDLER:
129                 registerJoinPoint(
130                         PointcutType.HANDLER,
131                         system,
132                         createClassInfo(declaringClass),
133                         withinInfo,
134                         joinPointMetaDataMap
135                 );
136                 break;
137             case JoinPointType.STATIC_INITALIZATION:
138                 throw new UnsupportedOperationException("not implemented");
139             default:
140                 throw new RuntimeException("join point type not valid");
141         }
142     }
143 
144     /***
145      * Returns the keys to the advices for the join point.
146      *
147      * @param classHash
148      * @param joinPointHash
149      * @return the advices attached to the join point
150      */
151     public Map getJoinPointMetaData(final long classHash, final long joinPointHash) {
152         TLongObjectHashMap joinPoints = (TLongObjectHashMap) m_joinPointMetaDataMap.get(classHash);
153         return (Map) joinPoints.get(joinPointHash);
154     }
155 
156     /***
157      * Returns the keys to the advices for the join point.
158      *
159      * @param classHash
160      * @param joinPointHash
161      * @return the advices attached to the join point
162      */
163     public Map getCflowPointcutsForJoinPoint(final long classHash, final long joinPointHash) {
164         TLongObjectHashMap joinPoints = (TLongObjectHashMap) m_joinPointCflowExpressionMap.get(classHash);
165         return (Map) joinPoints.get(joinPointHash);
166     }
167 
168     /***
169      * Resets the registry.
170      *
171      * @param classHash
172      * @TODO do better RW/RuW/JPredef eWorld brute force reset Needed since JoinPointRegistry is somehow a singleton
173      * (static in JoinPointManager)
174      */
175     public void reset(final int classHash) {
176         m_joinPointMetaDataMap.remove(classHash);
177         m_joinPointCflowExpressionMap.remove(classHash);
178     }
179 
180     /***
181      * Creates a class info instance out of a class instance.
182      *
183      * @param klass
184      * @return class info
185      */
186     private ClassInfo createClassInfo(final Class klass) {
187         ClassInfo classInfo = JavaClassInfoRepository.getRepository(klass.getClassLoader()).getClassInfo(
188                 klass.getName()
189         );
190         if (classInfo == null) {
191             classInfo = JavaClassInfo.getClassInfo(klass);
192         }
193         return classInfo;
194     }
195 
196     /***
197      * Register field get join points.
198      *
199      * @param type
200      * @param system
201      * @param reflectInfo
202      * @param withinInfo
203      * @param joinPointMetaDataMap
204      */
205     private void registerJoinPoint(final PointcutType type,
206                                    final AspectSystem system,
207                                    final ReflectionInfo reflectInfo,
208                                    final ReflectionInfo withinInfo,
209                                    final Map joinPointMetaDataMap) {
210         List adviceIndexInfoList = new ArrayList();
211         List cflowExpressionList = new ArrayList();
212         Pointcut cflowPointcut = null;
213         ExpressionContext ctx = new ExpressionContext(type, reflectInfo, withinInfo);
214         AspectManager[] aspectManagers = system.getAspectManagers();
215         for (int i = 0; i < aspectManagers.length; i++) {
216             AspectManager aspectManager = aspectManagers[i];
217 
218             /// grab the first one found, one single cflow pointcut is enough per join point
219             if (cflowPointcut == null) {
220                 List cflowPointcuts = aspectManager.getCflowPointcuts(ctx);
221                 if (!cflowPointcuts.isEmpty()) {
222                     cflowPointcut = (Pointcut) cflowPointcuts.get(0);
223                 }
224             }
225 
226             // get all matching pointcuts from all managers
227             for (Iterator it = aspectManager.getPointcuts(ctx).iterator(); it.hasNext();) {
228                 Pointcut pointcut = (Pointcut) it.next();
229                 AdviceInfo[] aroundAdviceIndexes = pointcut.getAroundAdviceIndexes();
230                 AdviceInfo[] beforeAdviceIndexes = pointcut.getBeforeAdviceIndexes();
231                 AdviceInfo[] afterAdviceIndexes = pointcut.getAfterFinallyAdviceIndexes();
232 
233                 AdviceIndexInfo adviceIndexInfo = new AdviceIndexInfo(
234                         aroundAdviceIndexes,
235                         pointcut.getBeforeAdviceIndexes(),
236                         pointcut.getAfterFinallyAdviceIndexes(),
237                         pointcut.getAfterReturningAdviceIndexes(),
238                         pointcut.getAfterThrowingAdviceIndexes()
239                 );
240 
241                 // args() support
242                 // TODO refactor from JPMetaData used in inlining weaving
243                 // compute target args to advice args mapping, it is a property of each *advice*
244 
245                 // refresh the arg index map
246                 pointcut.getExpressionInfo().getArgsIndexMapper().match(ctx);
247 
248                 //TODO can we do cache, can we do in another visitor
249                 //TODO skip map when no args()
250                 for (int j = 0; j < beforeAdviceIndexes.length; j++) {
251                     AdviceInfo indexTuple = beforeAdviceIndexes[j];
252                     String adviceName = pointcut.getBeforeAdviceName(j);
253 
254                     //grab the parameters names
255                     String[] adviceArgNames = JoinPointMetaData.getParameterNames(adviceName);
256 
257                     // map them from the ctx info
258                     int[] adviceToTargetArgs = new int[adviceArgNames.length];
259                     for (int k = 0; k < adviceArgNames.length; k++) {
260                         String adviceArgName = adviceArgNames[k];
261                         int exprArgIndex = pointcut.getExpressionInfo().getArgumentIndex(adviceArgName);
262                         if (exprArgIndex >= 0 && ctx.m_exprIndexToTargetIndex.containsKey(exprArgIndex)) {
263                             adviceToTargetArgs[k] = ctx.m_exprIndexToTargetIndex.get(exprArgIndex);
264                         } else {
265                             adviceToTargetArgs[k] = -1;
266                         }
267                     }
268                     //                    //debug:
269                     //                    for (int k = 0; k < adviceToTargetArgs.length; k++) {
270                     //                        int adviceToTargetArg = adviceToTargetArgs[k];
271                     //                        System.out.println(" " + k + " -> " + adviceToTargetArg);
272                     //                    }
273                     indexTuple.setMethodToArgIndexes(adviceToTargetArgs);
274                 }
275                 for (int j = 0; j < afterAdviceIndexes.length; j++) {
276                     AdviceInfo indexTuple = afterAdviceIndexes[j];
277                     String adviceName = pointcut.getAfterFinallyAdviceName(j);
278 
279                     //grab the parameters names
280                     String[] adviceArgNames = JoinPointMetaData.getParameterNames(adviceName);
281 
282                     // map them from the ctx info
283                     int[] adviceToTargetArgs = new int[adviceArgNames.length];
284                     for (int k = 0; k < adviceArgNames.length; k++) {
285                         String adviceArgName = adviceArgNames[k];
286                         int exprArgIndex = pointcut.getExpressionInfo().getArgumentIndex(adviceArgName);
287                         if (exprArgIndex >= 0 && ctx.m_exprIndexToTargetIndex.containsKey(exprArgIndex)) {
288                             adviceToTargetArgs[k] = ctx.m_exprIndexToTargetIndex.get(exprArgIndex);
289                         } else {
290                             adviceToTargetArgs[k] = -1;
291                         }
292                     }
293                     //                    //debug:
294                     //                    for (int k = 0; k < adviceToTargetArgs.length; k++) {
295                     //                        int adviceToTargetArg = adviceToTargetArgs[k];
296                     //                        System.out.println(" " + k + " -> " + adviceToTargetArg);
297                     //                    }
298                     indexTuple.setMethodToArgIndexes(adviceToTargetArgs);
299                 }
300 
301                 for (int j = 0; j < aroundAdviceIndexes.length; j++) {
302                     AdviceInfo indexTuple = aroundAdviceIndexes[j];
303                     String adviceName = pointcut.getAroundAdviceName(j);
304 
305                     //grab the parameters names
306                     String[] adviceArgNames = JoinPointMetaData.getParameterNames(adviceName);
307 
308                     // map them from the ctx info
309                     int[] adviceToTargetArgs = new int[adviceArgNames.length];
310                     for (int k = 0; k < adviceArgNames.length; k++) {
311                         String adviceArgName = adviceArgNames[k];
312                         int exprArgIndex = pointcut.getExpressionInfo().getArgumentIndex(adviceArgName);
313                         if (exprArgIndex >= 0 && ctx.m_exprIndexToTargetIndex.containsKey(exprArgIndex)) {
314                             adviceToTargetArgs[k] = ctx.m_exprIndexToTargetIndex.get(exprArgIndex);
315                         } else {
316                             adviceToTargetArgs[k] = -1;
317                         }
318                     }
319                     //                    //debug:
320                     //                    for (int k = 0; k < adviceToTargetArgs.length; k++) {
321                     //                        int adviceToTargetArg = adviceToTargetArgs[k];
322                     //                        System.out.println(" " + k + " -> " + adviceToTargetArg);
323                     //                    }
324                     indexTuple.setMethodToArgIndexes(adviceToTargetArgs);
325                 }
326 
327                 adviceIndexInfoList.add(adviceIndexInfo);
328 
329                 // collect the cflow expressions for the matching pointcuts (if they have one)
330                 if (pointcut.getExpressionInfo().hasCflowPointcut()) {
331                     cflowExpressionList.add(pointcut.getExpressionInfo().getCflowExpressionRuntime());
332                 }
333             }
334         }
335 
336         // turn the lists into arrays for performance reasons
337         AdviceIndexInfo[] adviceIndexInfo = new AdviceIndexInfo[adviceIndexInfoList.size()];
338         int i = 0;
339         for (Iterator iterator = adviceIndexInfoList.iterator(); iterator.hasNext(); i++) {
340             adviceIndexInfo[i] = (AdviceIndexInfo) iterator.next();
341         }
342         JoinPointMetaData metaData = new JoinPointMetaData();
343         metaData.adviceIndexes = adviceIndexInfo;
344         metaData.cflowExpressions = cflowExpressionList;
345         metaData.cflowPointcut = cflowPointcut;
346         metaData.expressionContext = ctx;
347         joinPointMetaDataMap.put(type, metaData);
348     }
349 }