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.ConstructorTuple;
12  import org.codehaus.aspectwerkz.AdviceInfo;
13  import org.codehaus.aspectwerkz.MethodTuple;
14  import org.codehaus.aspectwerkz.SystemLoader;
15  import org.codehaus.aspectwerkz.aspect.management.AspectRegistry;
16  import org.codehaus.aspectwerkz.aspect.management.Pointcut;
17  import org.codehaus.aspectwerkz.expression.PointcutType;
18  import org.codehaus.aspectwerkz.joinpoint.CodeRtti;
19  import org.codehaus.aspectwerkz.joinpoint.FieldRtti;
20  import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
21  import org.codehaus.aspectwerkz.joinpoint.Rtti;
22  import org.codehaus.aspectwerkz.joinpoint.CatchClauseRtti;
23  import org.codehaus.aspectwerkz.joinpoint.impl.CatchClauseRttiImpl;
24  import org.codehaus.aspectwerkz.joinpoint.impl.CatchClauseSignatureImpl;
25  import org.codehaus.aspectwerkz.joinpoint.impl.ConstructorRttiImpl;
26  import org.codehaus.aspectwerkz.joinpoint.impl.ConstructorSignatureImpl;
27  import org.codehaus.aspectwerkz.joinpoint.impl.FieldRttiImpl;
28  import org.codehaus.aspectwerkz.joinpoint.impl.FieldSignatureImpl;
29  import org.codehaus.aspectwerkz.joinpoint.impl.MethodRttiImpl;
30  import org.codehaus.aspectwerkz.joinpoint.impl.MethodSignatureImpl;
31  import org.codehaus.aspectwerkz.reflect.ClassInfo;
32  import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
33  import org.codehaus.aspectwerkz.reflect.MemberInfo;
34  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
35  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfoRepository;
36  import org.codehaus.aspectwerkz.transform.TransformationConstants;
37  
38  import java.lang.reflect.Field;
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Stack;
45  
46  //import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
47  //import EDU.oswego.cs.dl.util.concurrent.ReaderPreferenceReadWriteLock;
48  
49  /***
50   * Manages the join points, invokes the correct advice chains, handles redeployment, JIT compilation etc. Each advised
51   * class' instance holds one instance of this class.
52   * 
53   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
54   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
55   */
56  public class JoinPointManager {
57      /***
58       * The JIT compilation boundry for nr of method invocations before optimizing a certain method.
59       */
60      private static final long JIT_COMPILATION_BOUNDRY;
61  
62      /***
63       * Turns on/off the JIT compiler.
64       */
65      private static final boolean ENABLE_JIT_COMPILATION;
66  
67      static {
68          String noJIT = java.lang.System.getProperty("aspectwerkz.jit.off");
69          if (((noJIT != null) && ("true".equalsIgnoreCase(noJIT) || "yes".equalsIgnoreCase(noJIT)))) {
70              ENABLE_JIT_COMPILATION = false;
71          } else {
72              ENABLE_JIT_COMPILATION = true;
73          }
74          String boundry = java.lang.System.getProperty("aspectwerkz.jit.boundry");
75          if (boundry != null) {
76              JIT_COMPILATION_BOUNDRY = new Long(boundry).longValue();
77          } else {
78              JIT_COMPILATION_BOUNDRY = 1L;
79          }
80      }
81  
82      /***
83       * Block size of the join point index repository grow algorithm.
84       */
85      private static final int JOIN_POINT_INDEX_GROW_BLOCK = 10;
86  
87      private static final Map s_managers = new HashMap();
88  
89      private static final JoinPointRegistry s_registry = new JoinPointRegistry();
90  
91      private final JavaClassInfoRepository m_classInfoRepository;
92  
93      private final AspectSystem m_system;
94  
95      private final Class m_targetClass;
96  
97      private final int m_classHash;
98  
99      private int m_hotswapCount = 0;
100 
101     private ThreadLocal[] m_joinPoints = new ThreadLocal[0];
102 
103     //    private final ReadWriteLock m_readWriteLock = new ReaderPreferenceReadWriteLock();
104 
105     /***
106      * Creates a new join point manager for a specific class.
107      * 
108      * @param targetClass
109      */
110     private JoinPointManager(final Class targetClass) {
111         m_system = SystemLoader.getSystem(targetClass.getClassLoader());
112         m_targetClass = targetClass;
113         m_classHash = m_targetClass.hashCode();
114         m_classInfoRepository = JavaClassInfoRepository.getRepository(targetClass.getClassLoader());
115         m_hotswapCount = 0;
116     }
117 
118     /***
119      * Creates a new join point manager for a specific class.
120      * 
121      * @param targetClass
122      * @param hotswapCount
123      */
124     private JoinPointManager(final Class targetClass, int hotswapCount) {
125         m_system = SystemLoader.getSystem(targetClass.getClassLoader());
126         m_targetClass = targetClass;
127         m_classHash = m_targetClass.hashCode();
128         m_classInfoRepository = JavaClassInfoRepository.getRepository(targetClass.getClassLoader());
129         m_hotswapCount = hotswapCount;
130     }
131 
132     /***
133      * Returns the join point manager for a specific class.
134      * 
135      * @param targetClass
136      * @param uuid
137      * @return the join point manager instance for this class
138      * @TODO: UUID is not use or needed anymore, remove it from the TFs
139      */
140     public final static JoinPointManager getJoinPointManager(final Class targetClass, final String uuid) {
141         if (s_managers.containsKey(targetClass)) { //TODO AVAOPC should be Weak ?
142             return (JoinPointManager) s_managers.get(targetClass);
143         } else {
144             JoinPointManager manager = new JoinPointManager(targetClass);
145             s_managers.put(targetClass, manager);
146             return manager;
147         }
148     }
149 
150     /***
151      * Returs the join point registry.
152      * 
153      * @return the join point registry
154      */
155     public static JoinPointRegistry getJoinPointRegistry() {
156         return s_registry;
157     }
158 
159     /***
160      * Checks if a join point is advised, this does not mean that it has any advices attached to it. <p/>This method
161      * should be used by inserting a check in the wrapper/proxy method similar to this:
162      * 
163      * <pre>
164      * if (___AW_joinPointManager.hasAdvices(joinPointHash)) {
165      *     // execute the advice chain
166      * } else {
167      *     // invoke the prefixed target method
168      * }
169      * </pre>
170      * 
171      * @param joinPointHash
172      * @return
173      */
174     public boolean isAdvised(final int joinPointHash) {
175         // TODO: impl.
176         return true;
177 
178         //        return s_registry.getStateForJoinPoint(m_classHash, joinPointHash) >
179         // JoinPointState.NOT_ADVISED;
180     }
181 
182     /***
183      * Proceeds with the invocation of the join point, passing on the method hash, the parameter values and the target
184      * instance.
185      * 
186      * @param methodHash
187      * @param joinPointIndex
188      * @param parameters
189      * @param targetInstance
190      * @param joinPointType
191      * @return @throws Throwable
192      */
193     public final Object proceedWithExecutionJoinPoint(
194         final int methodHash,
195         final int joinPointIndex,
196         final Object[] parameters,
197         final Object targetInstance,
198         final int joinPointType) throws Throwable {
199         ThreadLocal threadLocal;
200         if (joinPointIndex < 0) {
201             throw new RuntimeException();
202         }
203 
204         //        m_readWriteLock.writeLock().acquire();
205         synchronized (m_joinPoints) {
206             //        try {
207             if ((joinPointIndex >= m_joinPoints.length) || (m_joinPoints[joinPointIndex] == null)) {
208                 s_registry.registerJoinPoint(
209                     joinPointType,
210                     methodHash,
211                     null,
212                     m_classHash,
213                     m_targetClass,
214                     null,//will be set to target method info
215                     m_system);
216                 threadLocal = new ThreadLocal();
217                 if (m_joinPoints.length <= joinPointIndex) {
218                     ThreadLocal[] tmp = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
219                     java.lang.System.arraycopy(m_joinPoints, 0, tmp, 0, m_joinPoints.length);
220                     m_joinPoints = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
221                     java.lang.System.arraycopy(tmp, 0, m_joinPoints, 0, tmp.length);
222                 }
223                 m_joinPoints[joinPointIndex] = threadLocal;
224             } else {
225                 threadLocal = m_joinPoints[joinPointIndex];
226             }
227         }
228 
229         //        } finally {
230         //            m_readWriteLock.writeLock().release();
231         //        }
232         //
233         JoinPointInfo joinPointInfo = (JoinPointInfo) threadLocal.get();
234         if (joinPointInfo == null) {
235             joinPointInfo = new JoinPointInfo();
236             threadLocal.set(joinPointInfo);
237         }
238         if (ENABLE_JIT_COMPILATION && !joinPointInfo.isJitCompiled) {
239             handleJitCompilation(
240                 methodHash,
241                 joinPointType,
242                 PointcutType.EXECUTION,
243                 joinPointInfo,
244                 m_targetClass,                      
245                 m_targetClass,
246                 targetInstance,
247                 targetInstance);
248         }
249         JoinPoint joinPoint = joinPointInfo.joinPoint;
250 
251         // if null or redefined -> create a new join point and cache it
252         if (joinPoint == null) {
253             Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, methodHash);
254             JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(PointcutType.EXECUTION);
255             AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
256             List cflowExpressions = joinPointMetaData.cflowExpressions;
257             Pointcut cflowPointcut = joinPointMetaData.cflowPointcut;
258             initCflowManagement(cflowPointcut, joinPointInfo);
259             switch (joinPointType) {
260                 case JoinPointType.METHOD_EXECUTION:
261                     joinPoint = createMethodJoinPoint(
262                         methodHash,
263                         joinPointType,
264                         m_targetClass,
265                         adviceIndexes,
266                         joinPointMetaData,
267                         targetInstance,
268                         targetInstance);
269                     break;
270                 case JoinPointType.CONSTRUCTOR_EXECUTION:
271                     joinPoint = createConstructorJoinPoint(
272                         methodHash,
273                         joinPointType,
274                         m_targetClass,
275                         adviceIndexes,
276                         joinPointMetaData,
277                         targetInstance,
278                         targetInstance);
279                     break;
280                 default:
281                     throw new RuntimeException("join point type not valid");
282             }
283 
284             // set the join point
285             joinPointInfo.joinPoint = joinPoint;
286 
287             // update the state
288             if (adviceIndexes.length == 0) {
289                 joinPointInfo.state = JoinPointState.ADVISED;
290             } else {
291                 joinPointInfo.state = JoinPointState.HAS_ADVICES;
292             }
293         }
294 
295         // set the RTTI
296         Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);
297         if (parameters != null) {
298             ((CodeRtti) rtti).setParameterValues(parameters);
299         }
300         setRtti(joinPointInfo, rtti);
301         enterCflow(joinPointInfo);
302         try {
303             return joinPoint.proceed();
304         } finally {
305             unsetRtti(joinPointInfo);
306             exitCflow(joinPointInfo);
307         }
308     }
309 
310     /***
311      * Proceeds with the invocation of the join point, passing on the method hash, the parameter values and the target
312      * instance.
313      * 
314      * @param methodHash
315      * @param joinPointIndex
316      * @param parameters
317      * @param targetClass
318      * @param targetInstance
319      * @param thisClass
320      * @param thisInstance
321      * @param withinMethodName
322      * @param withinMethodSignature
323      * @param joinPointType
324      * @return the result from the method invocation
325      * @throws Throwable
326      */
327     public final Object proceedWithCallJoinPoint(
328         final int methodHash,
329         final int joinPointIndex,
330         final Object[] parameters,
331         final Class targetClass,
332         final Object targetInstance,
333         final Class thisClass,
334         final Object thisInstance,
335         final String withinMethodName,
336         final String withinMethodSignature,
337         final int joinPointType) throws Throwable {
338         ThreadLocal threadLocal;
339         synchronized (m_joinPoints) {
340             if ((joinPointIndex >= m_joinPoints.length) || (m_joinPoints[joinPointIndex] == null)) {
341                 MemberInfo withinMemberInfo = ClassInfoHelper.createMemberInfo(
342                     targetClass,
343                     withinMethodName,
344                     withinMethodSignature);
345                 s_registry.registerJoinPoint(
346                     joinPointType,
347                     methodHash,
348                     null,
349                     m_classHash,
350                     thisClass,
351                     withinMemberInfo,
352                     m_system);
353                 threadLocal = new ThreadLocal();
354                 if (m_joinPoints.length <= joinPointIndex) {
355                     ThreadLocal[] tmp = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
356                     java.lang.System.arraycopy(m_joinPoints, 0, tmp, 0, m_joinPoints.length);
357                     m_joinPoints = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
358                     java.lang.System.arraycopy(tmp, 0, m_joinPoints, 0, tmp.length);
359                 }
360                 m_joinPoints[joinPointIndex] = threadLocal;
361             } else {
362                 threadLocal = m_joinPoints[joinPointIndex];
363             }
364         }
365         JoinPointInfo joinPointInfo = (JoinPointInfo) threadLocal.get();
366         if (joinPointInfo == null) {
367             joinPointInfo = new JoinPointInfo();
368             threadLocal.set(joinPointInfo);
369         }
370 
371         // TODO: make diff between target and this instances
372         if (ENABLE_JIT_COMPILATION && !joinPointInfo.isJitCompiled) {
373             handleJitCompilation(
374                 methodHash,
375                 joinPointType,
376                 PointcutType.CALL,
377                 joinPointInfo,
378                 thisClass,
379                 m_targetClass,
380                 thisInstance,
381                 thisInstance);
382         }
383         JoinPoint joinPoint = joinPointInfo.joinPoint;
384 
385         // if null or redefined -> create a new join point and cache it
386         if (joinPoint == null) {
387             Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, methodHash);
388             JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(PointcutType.CALL);
389             AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
390             List cflowExpressions = joinPointMetaData.cflowExpressions;
391             Pointcut cflowPointcut = joinPointMetaData.cflowPointcut;
392             initCflowManagement(cflowPointcut, joinPointInfo);
393             switch (joinPointType) {
394                 case JoinPointType.METHOD_CALL:
395 
396                     // TODO: make diff between target and this instances
397                     joinPoint = createMethodJoinPoint(
398                         methodHash,
399                         joinPointType,
400                         thisClass,
401                         adviceIndexes,
402                         joinPointMetaData,
403                         thisInstance,
404                         thisInstance);
405                     break;
406                 case JoinPointType.CONSTRUCTOR_CALL:
407 
408                     // TODO: make diff between target and this instances
409                     joinPoint = createConstructorJoinPoint(
410                         methodHash,
411                         joinPointType,
412                         thisClass,
413                         adviceIndexes,
414                         joinPointMetaData,
415                         thisInstance,
416                         thisInstance);
417                     break;
418                 default:
419                     throw new RuntimeException("join point type not valid");
420             }
421 
422             // set the join point
423             joinPointInfo.joinPoint = joinPoint;
424 
425             // update the state
426             if (adviceIndexes.length == 0) {
427                 joinPointInfo.state = JoinPointState.ADVISED;
428             } else {
429                 joinPointInfo.state = JoinPointState.HAS_ADVICES;
430             }
431         }
432 
433         Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, thisInstance);//AW-265
434         if (parameters != null) {
435             ((CodeRtti) rtti).setParameterValues(parameters);
436         }
437         setRtti(joinPointInfo, rtti);
438         enterCflow(joinPointInfo);
439         try {
440             return joinPoint.proceed();
441         } finally {
442             unsetRtti(joinPointInfo);
443             exitCflow(joinPointInfo);
444         }
445     }
446 
447     /***
448      * Proceeds with the invocation of the join point, passing on the method hash, the parameter values and the target
449      * instance.
450      * 
451      * @param fieldHash
452      * @param joinPointIndex
453      * @param fieldValue as the first arg in an Object array
454      * @param targetInstance
455      * @param declaringClass
456      * @param fieldSignature
457      * @throws Throwable
458      */
459     public final void proceedWithSetJoinPoint(
460         final int fieldHash,
461         final int joinPointIndex,
462         final Object[] fieldValue,
463         final Object targetInstance,
464         final Class declaringClass,
465         final String fieldSignature) throws Throwable {
466         ThreadLocal threadLocal;
467         synchronized (m_joinPoints) {
468             if ((joinPointIndex >= m_joinPoints.length) || (m_joinPoints[joinPointIndex] == null)) {
469                 s_registry.registerJoinPoint(
470                     JoinPointType.FIELD_SET,
471                     fieldHash,
472                     fieldSignature,
473                     m_classHash,
474                     declaringClass,
475                     null,//AVAJ within/withincode support ?
476                     m_system);
477                 threadLocal = new ThreadLocal();
478                 if (m_joinPoints.length <= joinPointIndex) {
479                     ThreadLocal[] tmp = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
480                     java.lang.System.arraycopy(m_joinPoints, 0, tmp, 0, m_joinPoints.length);
481                     m_joinPoints = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
482                     java.lang.System.arraycopy(tmp, 0, m_joinPoints, 0, tmp.length);
483                 }
484                 m_joinPoints[joinPointIndex] = threadLocal;
485             } else {
486                 threadLocal = m_joinPoints[joinPointIndex];
487             }
488         }
489         JoinPointInfo joinPointInfo = (JoinPointInfo) threadLocal.get();
490         if (joinPointInfo == null) {
491             joinPointInfo = new JoinPointInfo();
492             threadLocal.set(joinPointInfo);
493         }
494         if (ENABLE_JIT_COMPILATION && !joinPointInfo.isJitCompiled) {
495             handleJitCompilation(
496                 fieldHash,
497                 JoinPointType.FIELD_SET,
498                 PointcutType.SET,
499                 joinPointInfo,
500                 declaringClass,
501                 m_targetClass,
502                 targetInstance,
503                 targetInstance);
504         }
505         JoinPoint joinPoint = joinPointInfo.joinPoint;
506 
507         // if null or redefined -> create a new join point and cache it
508         if (joinPoint == null) {
509             Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, fieldHash);
510             JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(PointcutType.SET);
511             AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
512             List cflowExpressions = joinPointMetaData.cflowExpressions;
513             Pointcut cflowPointcut = joinPointMetaData.cflowPointcut;
514             initCflowManagement(cflowPointcut, joinPointInfo);
515             joinPoint = createFieldJoinPoint(
516                 fieldHash,
517                 JoinPointType.FIELD_SET,
518                 m_targetClass,
519                 adviceIndexes,
520                 joinPointMetaData,
521                 targetInstance,
522                 targetInstance);
523 
524             // set the join point
525             joinPointInfo.joinPoint = joinPoint;
526 
527             // update the state
528             if (adviceIndexes.length == 0) {
529                 joinPointInfo.state = JoinPointState.ADVISED;
530             } else {
531                 joinPointInfo.state = JoinPointState.HAS_ADVICES;
532             }
533         }
534 
535         // intialize the join point before each usage
536         Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);//AW-265
537         if (fieldValue[0] != null) {
538             ((FieldRtti) rtti).setFieldValue(fieldValue[0]);
539             // array due to sucky javassist field handling
540         }
541         setRtti(joinPointInfo, rtti);
542         enterCflow(joinPointInfo);
543         try {
544             joinPoint.proceed();
545         } finally {
546             unsetRtti(joinPointInfo);
547             exitCflow(joinPointInfo);
548         }
549     }
550 
551     /***
552      * Proceeds with the invocation of the join point, passing on the method hash, the parameter values and the target
553      * instance.
554      * 
555      * @param fieldHash
556      * @param joinPointIndex
557      * @param targetInstance
558      * @param declaringClass
559      * @param fieldSignature
560      * @throws Throwable
561      */
562     public final Object proceedWithGetJoinPoint(
563         final int fieldHash,
564         final int joinPointIndex,
565         final Object targetInstance,
566         final Class declaringClass,
567         final String fieldSignature) throws Throwable {
568         ThreadLocal threadLocal;
569         synchronized (m_joinPoints) {
570             if ((joinPointIndex >= m_joinPoints.length) || (m_joinPoints[joinPointIndex] == null)) {
571                 s_registry.registerJoinPoint(
572                     JoinPointType.FIELD_GET,
573                     fieldHash,
574                     fieldSignature,
575                     m_classHash,
576                     declaringClass,
577                     null,//AVAJ within/withincode support ?
578                     m_system);
579                 threadLocal = new ThreadLocal();
580                 if (m_joinPoints.length <= joinPointIndex) {
581                     ThreadLocal[] tmp = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
582                     java.lang.System.arraycopy(m_joinPoints, 0, tmp, 0, m_joinPoints.length);
583                     m_joinPoints = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
584                     java.lang.System.arraycopy(tmp, 0, m_joinPoints, 0, tmp.length);
585                 }
586                 m_joinPoints[joinPointIndex] = threadLocal;
587             } else {
588                 threadLocal = m_joinPoints[joinPointIndex];
589             }
590         }
591         JoinPointInfo joinPointInfo = (JoinPointInfo) threadLocal.get();
592         if (joinPointInfo == null) {
593             joinPointInfo = new JoinPointInfo();
594             threadLocal.set(joinPointInfo);
595         }
596         if (ENABLE_JIT_COMPILATION && !joinPointInfo.isJitCompiled) {
597             handleJitCompilation(
598                 fieldHash,
599                 JoinPointType.FIELD_GET,
600                 PointcutType.GET,
601                 joinPointInfo,
602                 declaringClass,
603                 m_targetClass,
604                 targetInstance,
605                 targetInstance);
606         }
607         JoinPoint joinPoint = joinPointInfo.joinPoint;
608 
609         // if null or redefined -> create a new join point and cache it
610         if (joinPoint == null) {
611             Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, fieldHash);
612             JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(PointcutType.GET);
613             AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
614             List cflowExpressions = joinPointMetaData.cflowExpressions;
615             Pointcut cflowPointcut = joinPointMetaData.cflowPointcut;
616             initCflowManagement(cflowPointcut, joinPointInfo);
617             joinPoint = createFieldJoinPoint(
618                 fieldHash,
619                 JoinPointType.FIELD_GET,
620                 m_targetClass,
621                 adviceIndexes,
622                 joinPointMetaData,
623                 targetInstance,
624                 targetInstance);
625 
626             // set the join point
627             joinPointInfo.joinPoint = joinPoint;
628 
629             // update the state
630             if (adviceIndexes.length == 0) {
631                 joinPointInfo.state = JoinPointState.ADVISED;
632             } else {
633                 joinPointInfo.state = JoinPointState.HAS_ADVICES;
634             }
635         }
636 
637         // intialize the join point before each usage
638         Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);//AW-265
639         setRtti(joinPointInfo, rtti);
640         enterCflow(joinPointInfo);
641         try {
642             return joinPoint.proceed();
643         } finally {
644             unsetRtti(joinPointInfo);
645             exitCflow(joinPointInfo);
646         }
647     }
648 
649     /***
650      * Proceeds with the invocation of the join point, passing on the method hash, the parameter values and the target
651      * instance.
652      * 
653      * @param handlerHash
654      * @param joinPointIndex
655      * @param exceptionInstance
656      * @param targetInstance
657      * @param handlerSignature
658      * @throws Throwable
659      */
660     public final void proceedWithHandlerJoinPoint(
661         final int handlerHash,
662         final int joinPointIndex,
663         final Object exceptionInstance,
664         final Object targetInstance,
665         final String handlerSignature) throws Throwable {
666         ThreadLocal threadLocal;
667         synchronized (m_joinPoints) {
668             if ((joinPointIndex >= m_joinPoints.length) || (m_joinPoints[joinPointIndex] == null)) {
669                 ClassInfo withinClassInfo = createClassInfo(m_targetClass);//AVAJ within/withincode support ?
670                 s_registry.registerJoinPoint(
671                     JoinPointType.HANDLER,
672                     handlerHash,
673                     handlerSignature,
674                     m_classHash,
675                     exceptionInstance.getClass(),
676                     withinClassInfo,
677                     m_system);
678                 threadLocal = new ThreadLocal();
679                 if (m_joinPoints.length <= joinPointIndex) {
680                     ThreadLocal[] tmp = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
681                     java.lang.System.arraycopy(m_joinPoints, 0, tmp, 0, m_joinPoints.length);
682                     m_joinPoints = new ThreadLocal[joinPointIndex + JOIN_POINT_INDEX_GROW_BLOCK];
683                     java.lang.System.arraycopy(tmp, 0, m_joinPoints, 0, tmp.length);
684                 }
685                 m_joinPoints[joinPointIndex] = threadLocal;
686             } else {
687                 threadLocal = m_joinPoints[joinPointIndex];
688             }
689         }
690         JoinPointInfo joinPointInfo = (JoinPointInfo) threadLocal.get();
691         if (joinPointInfo == null) {
692             joinPointInfo = new JoinPointInfo();
693             threadLocal.set(joinPointInfo);
694         }
695         if (ENABLE_JIT_COMPILATION && !joinPointInfo.isJitCompiled) {
696             handleJitCompilation(
697                 handlerHash,
698                 JoinPointType.HANDLER,
699                 PointcutType.HANDLER,
700                 joinPointInfo,
701                 m_targetClass,
702                 m_targetClass,
703                 targetInstance,
704                 targetInstance);
705         }
706         JoinPoint joinPoint = joinPointInfo.joinPoint;
707 
708         // if null or redefined -> create a new join point and cache it
709         if (joinPoint == null) {
710             Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, handlerHash);
711             JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(PointcutType.HANDLER);
712             AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
713             List cflowExpressions = joinPointMetaData.cflowExpressions;
714             Pointcut cflowPointcut = joinPointMetaData.cflowPointcut;
715             initCflowManagement(cflowPointcut, joinPointInfo);
716             joinPoint = createCatchClauseJoinPoint(
717                 exceptionInstance.getClass(),
718                 m_targetClass,
719                 handlerSignature,
720                 adviceIndexes,
721                 joinPointMetaData,
722                 targetInstance,
723                 targetInstance);
724 
725             // set the join point
726             joinPointInfo.joinPoint = joinPoint;
727 
728             // update the state
729             if (adviceIndexes.length == 0) {
730                 joinPointInfo.state = JoinPointState.ADVISED;
731             } else {
732                 joinPointInfo.state = JoinPointState.HAS_ADVICES;
733             }
734         }
735 
736         // intialize the join point before each usage
737         Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);//AW-265
738         ((CatchClauseRtti)rtti).setParameterValue(exceptionInstance);
739         setRtti(joinPointInfo, rtti);
740         enterCflow(joinPointInfo);
741         try {
742             joinPoint.proceed();
743         } finally {
744             unsetRtti(joinPointInfo);
745             exitCflow(joinPointInfo);
746         }
747     }
748 
749     /***
750      * Creates a class info instance out of a class instance.
751      * 
752      * @param klass
753      * @return class info
754      */
755     private ClassInfo createClassInfo(final Class klass) {
756         ClassInfo classInfo = m_classInfoRepository.getClassInfo(klass.getName());
757         if (classInfo == null) {
758             classInfo = JavaClassInfo.getClassInfo(klass);
759         }
760         return classInfo;
761     }
762 
763     /***
764      * Handles the Just-In-Time (JIT) compilation of the advice execution chains.
765      * 
766      * @param joinPointHash
767      * @param joinPointType
768      * @param pointcutType
769      * @param joinPointInfo
770      * @param declaringClass
771      * @param targetClass
772      * @param thisInstance
773      * @param targetInstance
774      */
775     private final void handleJitCompilation(
776         final int joinPointHash,
777         final int joinPointType,
778         final PointcutType pointcutType,
779         final JoinPointInfo joinPointInfo,
780         final Class declaringClass,
781         final Class targetClass,
782         final Object thisInstance,
783         final Object targetInstance) {
784         synchronized (joinPointInfo) {
785             joinPointInfo.invocations++;
786             if (joinPointInfo.state == JoinPointState.REDEFINED) {
787                 joinPointInfo.invocations = 0L;
788             } else if (joinPointInfo.invocations == JIT_COMPILATION_BOUNDRY) {
789                 Map joinPointMetaDataMap = s_registry.getJoinPointMetaData(m_classHash, joinPointHash);
790                 if (joinPointMetaDataMap.containsKey(pointcutType)) {
791                     JoinPointMetaData joinPointMetaData = (JoinPointMetaData) joinPointMetaDataMap.get(pointcutType);
792                     AdviceIndexInfo[] adviceIndexes = joinPointMetaData.adviceIndexes;
793                     joinPointInfo.joinPoint = JitCompiler.compileJoinPoint(
794                         joinPointHash,
795                         joinPointType,
796                         pointcutType,
797                         adviceIndexes,
798                         declaringClass,
799                         targetClass,
800                         m_system,
801                         thisInstance,
802                         targetInstance,
803                         m_hotswapCount);
804                     joinPointInfo.isJitCompiled = true;
805                 }
806             }
807         }
808     }
809 
810     /***
811      * Create a method join point.
812      * 
813      * @param methodHash
814      * @param joinPointType
815      * @param declaringClass
816      * @param adviceIndexes
817      * @param joinPointMetaData
818      * @param thisInstance
819      * @param targetInstance
820      * @return
821      */
822     private final MethodJoinPoint createMethodJoinPoint(
823         final int methodHash,
824         final int joinPointType,
825         final Class declaringClass,
826         final AdviceIndexInfo[] adviceIndexes,
827         final JoinPointMetaData joinPointMetaData,
828         final Object thisInstance,
829         final Object targetInstance) {
830         MethodTuple methodTuple = AspectRegistry.getMethodTuple(declaringClass, methodHash);
831         Class declaringType = methodTuple.getDeclaringClass();
832         MethodSignatureImpl signature = new MethodSignatureImpl(declaringType, methodTuple);
833         Rtti rtti = new MethodRttiImpl(signature, thisInstance, targetInstance);
834         return new MethodJoinPoint(
835             joinPointType,
836             m_targetClass,
837             signature,
838             rtti,
839             joinPointMetaData,
840             createAroundAdviceExecutor(adviceIndexes, joinPointType),
841             createBeforeAdviceExecutor(adviceIndexes),
842             createAfterAdviceExecutor(adviceIndexes));
843     }
844 
845     /***
846      * Create a constructor join point.
847      * 
848      * @param constructorHash
849      * @param joinPointType
850      * @param declaringClass
851      * @param adviceIndexes
852      * @param joinPointMetaData
853      * @param thisInstance
854      * @param targetInstance
855      * @return
856      */
857     private final JoinPoint createConstructorJoinPoint(
858         final int constructorHash,
859         final int joinPointType,
860         final Class declaringClass,
861         final AdviceIndexInfo[] adviceIndexes,
862         final JoinPointMetaData joinPointMetaData,
863         final Object thisInstance,
864         final Object targetInstance) {
865         ConstructorTuple constructorTuple = AspectRegistry.getConstructorTuple(declaringClass, constructorHash);
866         Class declaringType = constructorTuple.getDeclaringClass();
867         ConstructorSignatureImpl signature = new ConstructorSignatureImpl(declaringType, constructorTuple);
868         Rtti rtti = new ConstructorRttiImpl(signature, thisInstance, targetInstance);
869         return new ConstructorJoinPoint(
870             joinPointType,
871             m_targetClass,
872             signature,
873             rtti,
874             joinPointMetaData,
875             createAroundAdviceExecutor(adviceIndexes, joinPointType),
876             createBeforeAdviceExecutor(adviceIndexes),
877             createAfterAdviceExecutor(adviceIndexes));
878     }
879 
880     /***
881      * Create a field join point.
882      * 
883      * @param fieldHash
884      * @param joinPointType
885      * @param declaringClass
886      * @param adviceIndexes
887      * @param joinPointMetaData
888      * @param thisInstance
889      * @param targetInstance
890      * @return
891      */
892     private final JoinPoint createFieldJoinPoint(
893         final int fieldHash,
894         final int joinPointType,
895         final Class declaringClass,
896         final AdviceIndexInfo[] adviceIndexes,
897         final JoinPointMetaData joinPointMetaData,
898         final Object thisInstance,
899         final Object targetInstance) {
900         Field field = AspectRegistry.getField(declaringClass, fieldHash);
901         FieldSignatureImpl signature = new FieldSignatureImpl(declaringClass, field);
902         Rtti rtti = new FieldRttiImpl(signature, thisInstance, targetInstance);
903         return new FieldJoinPoint(
904             joinPointType,
905             m_targetClass,
906             signature,
907             rtti,
908             joinPointMetaData,
909             createAroundAdviceExecutor(adviceIndexes, joinPointType),
910             createBeforeAdviceExecutor(adviceIndexes),
911             createAfterAdviceExecutor(adviceIndexes));
912     }
913 
914     /***
915      * Create a catch clause join point.
916      * 
917      * @param exceptionClass
918      * @param declaringClass
919      * @param catchClauseSignature
920      * @param adviceIndexes
921      * @param joinPointMetaData
922      * @param thisInstance
923      * @param targetInstance
924      * @return
925      */
926     private final JoinPoint createCatchClauseJoinPoint(
927         final Class exceptionClass,
928         final Class declaringClass,
929         final String catchClauseSignature,
930         final AdviceIndexInfo[] adviceIndexes,
931         final JoinPointMetaData joinPointMetaData,
932         final Object thisInstance,
933         final Object targetInstance) {
934         CatchClauseSignatureImpl signature = new CatchClauseSignatureImpl(
935             exceptionClass,
936             declaringClass,
937             catchClauseSignature);
938         Rtti rtti = new CatchClauseRttiImpl(signature, thisInstance, targetInstance);
939         return new CatchClauseJoinPoint(m_targetClass, signature, rtti, joinPointMetaData, createAroundAdviceExecutor(
940             adviceIndexes,
941             JoinPointType.HANDLER), createBeforeAdviceExecutor(adviceIndexes), createAfterAdviceExecutor(adviceIndexes));
942     }
943 
944     /***
945      * Creates an around advice executor.
946      * 
947      * @param adviceIndexes
948      * @param joinPointType
949      * @return the advice executor
950      */
951     private final AroundAdviceExecutor createAroundAdviceExecutor(
952         final AdviceIndexInfo[] adviceIndexes,
953         final int joinPointType) {
954         return new AroundAdviceExecutor(extractAroundAdvices(adviceIndexes), joinPointType);
955     }
956 
957     /***
958      * Creates a before advice executor.
959      * 
960      * @param adviceIndexes
961      * @return the advice executor
962      */
963     private final BeforeAdviceExecutor createBeforeAdviceExecutor(final AdviceIndexInfo[] adviceIndexes) {
964         return new BeforeAdviceExecutor(extractBeforeAdvices(adviceIndexes));
965     }
966 
967     /***
968      * Creates an after advice executor.
969      * 
970      * @param adviceIndexes
971      * @return the advice executor
972      */
973     private final AfterAdviceExecutor createAfterAdviceExecutor(final AdviceIndexInfo[] adviceIndexes) {
974         return new AfterAdviceExecutor(extractAfterFinallyAdvices(adviceIndexes));
975     }
976 
977     /***
978      * Extracts the around advices.
979      * 
980      * @param adviceIndexes
981      * @return
982      */
983     public final static AdviceInfo[] extractAroundAdvices(final AdviceIndexInfo[] adviceIndexes) {
984         int i;
985         int j;
986         List aroundAdviceList = new ArrayList();
987         for (i = 0; i < adviceIndexes.length; i++) {
988             AdviceIndexInfo adviceIndex = adviceIndexes[i];
989             AdviceInfo[] indexTuples = adviceIndex.getAroundAdvices();
990             for (j = 0; j < indexTuples.length; j++) {
991                 aroundAdviceList.add(indexTuples[j]);
992             }
993         }
994         AdviceInfo[] aroundAdvices = new AdviceInfo[aroundAdviceList.size()];
995         i = 0;
996         for (Iterator it = aroundAdviceList.iterator(); it.hasNext(); i++) {
997             aroundAdvices[i] = (AdviceInfo) it.next();
998         }
999         return aroundAdvices;
1000     }
1001 
1002     /***
1003      * Extracts the before advices.
1004      * 
1005      * @param adviceIndexes
1006      * @return
1007      */
1008     public final static AdviceInfo[] extractBeforeAdvices(final AdviceIndexInfo[] adviceIndexes) {
1009         int i;
1010         int j;
1011         List beforeAdviceList = new ArrayList();
1012         for (i = 0; i < adviceIndexes.length; i++) {
1013             AdviceIndexInfo adviceIndex = adviceIndexes[i];
1014             AdviceInfo[] indexTuples = adviceIndex.getBeforeAdvices();
1015             for (j = 0; j < indexTuples.length; j++) {
1016                 beforeAdviceList.add(indexTuples[j]);
1017             }
1018         }
1019         AdviceInfo[] beforeAdvices = new AdviceInfo[beforeAdviceList.size()];
1020         i = 0;
1021         for (Iterator it = beforeAdviceList.iterator(); it.hasNext(); i++) {
1022             beforeAdvices[i] = (AdviceInfo) it.next();
1023         }
1024         return beforeAdvices;
1025     }
1026 
1027     /***
1028      * Extracts the after finally advices.
1029      *
1030      * @param adviceIndexes
1031      * @return
1032      */
1033     public final static AdviceInfo[] extractAfterFinallyAdvices(final AdviceIndexInfo[] adviceIndexes) {
1034         int i;
1035         int j;
1036         List afterAdviceList = new ArrayList();
1037         for (i = 0; i < adviceIndexes.length; i++) {
1038             AdviceIndexInfo adviceIndex = adviceIndexes[i];
1039             AdviceInfo[] indexTuples = adviceIndex.getAfterFinallyAdvices();
1040             for (j = 0; j < indexTuples.length; j++) {
1041                 afterAdviceList.add(indexTuples[j]);
1042             }
1043         }
1044         AdviceInfo[] afterAdvices = new AdviceInfo[afterAdviceList.size()];
1045         i = 0;
1046         for (Iterator it = afterAdviceList.iterator(); it.hasNext(); i++) {
1047             afterAdvices[i] = (AdviceInfo) it.next();
1048         }
1049         return afterAdvices;
1050     }
1051 
1052     /***
1053      * Extracts the after returning advices.
1054      *
1055      * @param adviceIndexes
1056      * @return
1057      */
1058     public final static AdviceInfo[] extractAfterReturningAdvices(final AdviceIndexInfo[] adviceIndexes) {
1059         int i;
1060         int j;
1061         List afterAdviceList = new ArrayList();
1062         for (i = 0; i < adviceIndexes.length; i++) {
1063             AdviceIndexInfo adviceIndex = adviceIndexes[i];
1064             AdviceInfo[] indexTuples = adviceIndex.getAfterReturningAdvices();
1065             for (j = 0; j < indexTuples.length; j++) {
1066                 afterAdviceList.add(indexTuples[j]);
1067             }
1068         }
1069         AdviceInfo[] afterAdvices = new AdviceInfo[afterAdviceList.size()];
1070         i = 0;
1071         for (Iterator it = afterAdviceList.iterator(); it.hasNext(); i++) {
1072             afterAdvices[i] = (AdviceInfo) it.next();
1073         }
1074         return afterAdvices;
1075     }
1076 
1077     /***
1078      * Extracts the after throwing advices.
1079      *
1080      * @param adviceIndexes
1081      * @return
1082      */
1083     public final static AdviceInfo[] extractAfterThrowingAdvices(final AdviceIndexInfo[] adviceIndexes) {
1084         int i;
1085         int j;
1086         List afterAdviceList = new ArrayList();
1087         for (i = 0; i < adviceIndexes.length; i++) {
1088             AdviceIndexInfo adviceIndex = adviceIndexes[i];
1089             AdviceInfo[] indexTuples = adviceIndex.getAfterThrowingAdvices();
1090             for (j = 0; j < indexTuples.length; j++) {
1091                 afterAdviceList.add(indexTuples[j]);
1092             }
1093         }
1094         AdviceInfo[] afterAdvices = new AdviceInfo[afterAdviceList.size()];
1095         i = 0;
1096         for (Iterator it = afterAdviceList.iterator(); it.hasNext(); i++) {
1097             afterAdvices[i] = (AdviceInfo) it.next();
1098         }
1099         return afterAdvices;
1100     }
1101 
1102     /***
1103      * Reset the join point manager.
1104      * 
1105      * @param klass
1106      */
1107     public static synchronized void reset(Class klass) {
1108         JoinPointManager oldJoinPointManager = getJoinPointManager(klass, "N/A/runtime");
1109 
1110         // flush JP Registry
1111         s_registry.reset(klass.hashCode());
1112         JoinPointManager joinPointManager = new JoinPointManager(klass, oldJoinPointManager.m_hotswapCount + 1);
1113         s_managers.put(klass, joinPointManager);
1114         try {
1115             Field jpMan = klass.getDeclaredField(TransformationConstants.JOIN_POINT_MANAGER_FIELD);
1116             jpMan.setAccessible(true);
1117             jpMan.set(null, joinPointManager);
1118         } catch (Exception e) {
1119             System.err.println("ERROR: Unable to propagate JoinPointManager");
1120             e.printStackTrace();
1121         }
1122         joinPointManager.m_joinPoints = new ThreadLocal[0];
1123     }
1124 
1125     /***
1126      * Records entering into cflow.
1127      * 
1128      * @param joinPointInfo
1129      */
1130     private void enterCflow(final JoinPointInfo joinPointInfo) throws Throwable {
1131         AdviceInfo enter = joinPointInfo.enterCflow;
1132         if (enter != null) {
1133             enter.getAspectManager().getAspectContainer(enter.getAspectIndex()).invokeAdvice(
1134                 enter.getMethodIndex(),
1135                 joinPointInfo.joinPoint);
1136         }
1137     }
1138 
1139     /***
1140      * Records exiting from cflow.
1141      * 
1142      * @param joinPointInfo
1143      */
1144     private void exitCflow(final JoinPointInfo joinPointInfo) throws Throwable {
1145         AdviceInfo exit = joinPointInfo.exitCflow;
1146         if (exit != null) {
1147             exit.getAspectManager().getAspectContainer(exit.getAspectIndex()).invokeAdvice(
1148                 exit.getMethodIndex(),
1149                 joinPointInfo.joinPoint);
1150         }
1151     }
1152 
1153     /***
1154      * Initializes the cflow management.
1155      * 
1156      * @param cflowPointcut
1157      * @param joinPointInfo
1158      */
1159     private void initCflowManagement(final Pointcut cflowPointcut, final JoinPointInfo joinPointInfo) {
1160         if (cflowPointcut != null) {
1161             AdviceInfo[] beforeAdviceIndexes = cflowPointcut.getBeforeAdviceIndexes();
1162             AdviceInfo[] afterAdviceIndexes = cflowPointcut.getAfterFinallyAdviceIndexes();
1163             if ((beforeAdviceIndexes.length != 0) && (afterAdviceIndexes.length != 0)) {
1164                 joinPointInfo.enterCflow = beforeAdviceIndexes[0];
1165                 joinPointInfo.exitCflow = afterAdviceIndexes[0];
1166             }
1167         }
1168     }
1169 
1170     /***
1171      * Contains the JoinPoint instance and some RTTI about the join point.
1172      * This class is wrapped behing a ThreadLocal.
1173      * 
1174      */
1175     static class JoinPointInfo {
1176         public JoinPoint joinPoint = null;
1177 
1178         public int state = JoinPointState.NOT_ADVISED;
1179 
1180         public long invocations = 0L;
1181 
1182         public boolean isJitCompiled = false;
1183 
1184         public AdviceInfo enterCflow;
1185 
1186         public AdviceInfo exitCflow;
1187 
1188         /***
1189          * A stack of RTTI that allows us to keep RTTI even with reentrant target method call on other instances etc
1190          */
1191         public Stack rttiStack = new Stack();
1192     }
1193 
1194     /***
1195      * Helper method, pop the rtti from the stack and reset the JP with the next on stack
1196      *
1197      * @param joinPointInfo
1198      */
1199     private static void unsetRtti(final JoinPointInfo joinPointInfo) {
1200         JoinPoint joinPoint = joinPointInfo.joinPoint;
1201         // pop the old RTTI from the stack
1202         joinPointInfo.rttiStack.pop();
1203         // and peek the next one to pass it back to the joinpoint if there is one (else it means out of cflow)
1204         if (!joinPointInfo.rttiStack.isEmpty()) {
1205             ((JoinPointBase)joinPoint).setRtti((Rtti)joinPointInfo.rttiStack.peek());
1206         }
1207     }
1208 
1209     /***
1210      * Helper method, push the rtti to the stack and reset the jp with it
1211      *
1212      * @param joinPointInfo
1213      * @param rtti
1214      */
1215     private static void setRtti(final JoinPointInfo joinPointInfo, final Rtti rtti) {
1216         JoinPoint joinPoint = joinPointInfo.joinPoint;
1217         ((JoinPointBase)joinPoint).setRtti(rtti);
1218         joinPointInfo.rttiStack.push(rtti);
1219     }
1220 }