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
47
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
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)) {
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
176 return true;
177
178
179
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
205 synchronized (m_joinPoints) {
206
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,
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
230
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
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
285 joinPointInfo.joinPoint = joinPoint;
286
287
288 if (adviceIndexes.length == 0) {
289 joinPointInfo.state = JoinPointState.ADVISED;
290 } else {
291 joinPointInfo.state = JoinPointState.HAS_ADVICES;
292 }
293 }
294
295
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
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
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
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
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
423 joinPointInfo.joinPoint = joinPoint;
424
425
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);
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,
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
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
525 joinPointInfo.joinPoint = joinPoint;
526
527
528 if (adviceIndexes.length == 0) {
529 joinPointInfo.state = JoinPointState.ADVISED;
530 } else {
531 joinPointInfo.state = JoinPointState.HAS_ADVICES;
532 }
533 }
534
535
536 Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);
537 if (fieldValue[0] != null) {
538 ((FieldRtti) rtti).setFieldValue(fieldValue[0]);
539
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,
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
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
627 joinPointInfo.joinPoint = joinPoint;
628
629
630 if (adviceIndexes.length == 0) {
631 joinPointInfo.state = JoinPointState.ADVISED;
632 } else {
633 joinPointInfo.state = JoinPointState.HAS_ADVICES;
634 }
635 }
636
637
638 Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);
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);
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
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
726 joinPointInfo.joinPoint = joinPoint;
727
728
729 if (adviceIndexes.length == 0) {
730 joinPointInfo.state = JoinPointState.ADVISED;
731 } else {
732 joinPointInfo.state = JoinPointState.HAS_ADVICES;
733 }
734 }
735
736
737 Rtti rtti = joinPoint.getRtti().cloneFor(targetInstance, targetInstance);
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
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
1202 joinPointInfo.rttiStack.pop();
1203
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 }