KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > aop > aspectj > annotation > ReflectiveAspectJAdvisorFactory


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.aop.aspectj.annotation;
18
19 import java.lang.reflect.Field JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.LinkedList JavaDoc;
22 import java.util.List JavaDoc;
23
24 import org.aopalliance.aop.Advice;
25 import org.aspectj.lang.JoinPoint;
26 import org.aspectj.lang.ProceedingJoinPoint;
27 import org.aspectj.lang.annotation.AfterReturning;
28 import org.aspectj.lang.annotation.AfterThrowing;
29 import org.aspectj.lang.annotation.DeclareParents;
30 import org.aspectj.lang.annotation.Pointcut;
31
32 import org.springframework.aop.Advisor;
33 import org.springframework.aop.MethodBeforeAdvice;
34 import org.springframework.aop.aspectj.AbstractAspectJAdvice;
35 import org.springframework.aop.aspectj.AspectJAfterAdvice;
36 import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
37 import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
38 import org.springframework.aop.aspectj.AspectJAroundAdvice;
39 import org.springframework.aop.aspectj.AspectJExpressionPointcut;
40 import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
41 import org.springframework.aop.aspectj.DeclareParentsAdvisor;
42 import org.springframework.aop.framework.AopConfigException;
43 import org.springframework.aop.support.DefaultPointcutAdvisor;
44 import org.springframework.core.annotation.AnnotationUtils;
45 import org.springframework.util.ReflectionUtils;
46 import org.springframework.util.StringUtils;
47
48 /**
49  * Factory that can create Spring AOP Advisors given AspectJ classes from
50  * classes honoring the AspectJ 5 annotation syntax, using reflection to
51  * invoke the corresponding advice methods.
52  *
53  * @author Rod Johnson
54  * @author Adrian Colyer
55  * @author Juergen Hoeller
56  * @since 2.0
57  */

58 public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory {
59
60     public List JavaDoc<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
61         final Class JavaDoc<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
62         final String JavaDoc aspectName = maaif.getAspectMetadata().getAspectName();
63         validate(aspectClass);
64
65         // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
66
// so that it will only instantiate once.
67
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
68                 new LazySingletonAspectInstanceFactoryDecorator(maaif);
69
70         final List JavaDoc<Advisor> advisors = new LinkedList JavaDoc<Advisor>();
71         ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
72             public void doWith(Method JavaDoc method) throws IllegalArgumentException JavaDoc {
73                 // Exclude pointcuts
74
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
75                     Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
76                     if (advisor != null) {
77                         advisors.add(advisor);
78                     }
79                 }
80             }
81         });
82
83         // If it's a per target aspect, emit the dummy instantiating aspect.
84
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
85             Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
86             advisors.add(0, instantiationAdvisor);
87         }
88
89         // Find introduction fields.
90
for (Field JavaDoc field : aspectClass.getDeclaredFields()) {
91             Advisor advisor = getDeclareParentsAdvisor(field);
92             if (advisor != null) {
93                 advisors.add(advisor);
94             }
95         }
96
97         return advisors;
98     }
99
100     /**
101      * Build a {@link org.springframework.aop.aspectj.DeclareParentsAdvisor}
102      * for the given introduction field.
103      * <p>Resulting Advisors will need to be evaluated for targets.
104      * @param introductionField the field to introspect
105      * @return <code>null</code> if not an Advisor
106      */

107     private Advisor getDeclareParentsAdvisor(Field JavaDoc introductionField) {
108         DeclareParents declareParents = (DeclareParents) introductionField.getAnnotation(DeclareParents.class);
109         if (declareParents == null) {
110             // Not an introduction field
111
return null;
112         }
113
114         if (DeclareParents.class.equals(declareParents.defaultImpl())) {
115             // This is what comes back if it wasn't set. This seems bizarre...
116
// TODO this restriction possibly should be relaxed
117
throw new IllegalStateException JavaDoc("defaultImpl must be set on DeclareParents");
118         }
119
120         return new DeclareParentsAdvisor(
121                 introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
122     }
123
124
125     public Advisor getAdvisor(Method JavaDoc candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
126             int declarationOrderInAspect, String JavaDoc aspectName) {
127
128         validate(aif.getAspectMetadata().getAspectClass());
129
130         AspectJExpressionPointcut ajexp =
131                 getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
132         if (ajexp == null) {
133             return null;
134         }
135         return new InstantiationModelAwarePointcutAdvisorImpl(
136                 this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
137     }
138
139     private AspectJExpressionPointcut getPointcut(Method JavaDoc candidateAdviceMethod, Class JavaDoc<?> candidateAspectClass) {
140         AspectJAnnotation<?> aspectJAnnotation =
141                 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
142         if (aspectJAnnotation == null) {
143             return null;
144         }
145         AspectJExpressionPointcut ajexp =
146                 new AspectJExpressionPointcut(candidateAspectClass, new String JavaDoc[0], new Class JavaDoc[0]);
147         ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
148         return ajexp;
149     }
150
151
152     public Advice getAdvice(Method JavaDoc candidateAdviceMethod, AspectJExpressionPointcut ajexp,
153             MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String JavaDoc aspectName) {
154
155         Class JavaDoc<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
156         validate(candidateAspectClass);
157
158         AspectJAnnotation<?> aspectJAnnotation =
159                 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
160         if (aspectJAnnotation == null) {
161             return null;
162         }
163
164         // If we get here, we know we have an AspectJ method.
165
// Check that it's an AspectJ-annotated class
166
if (!isAspect(candidateAspectClass)) {
167             throw new AopConfigException("Advice must be declared inside an aspect type: " +
168                     "Offending method '" + candidateAdviceMethod + "' in class [" +
169                     candidateAspectClass.getName() + "]");
170         }
171
172         if (logger.isDebugEnabled()) {
173             logger.debug("Found AspectJ method: " + candidateAdviceMethod);
174         }
175
176         AbstractAspectJAdvice springAdvice;
177
178         switch (aspectJAnnotation.getAnnotationType()) {
179             case AtBefore:
180                 springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
181                 break;
182             case AtAfter:
183                 springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
184                 break;
185             case AtAfterReturning:
186                 springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
187                 AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
188                 if (StringUtils.hasText(afterReturningAnnotation.returning())) {
189                     springAdvice.setReturningName(afterReturningAnnotation.returning());
190                 }
191                 break;
192             case AtAfterThrowing:
193                 springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
194                 AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
195                 if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
196                     springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
197                 }
198                 break;
199             case AtAround:
200                 springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
201                 break;
202             case AtPointcut:
203                 if (logger.isDebugEnabled()) {
204                     logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
205                 }
206                 return null;
207             default:
208                 throw new UnsupportedOperationException JavaDoc(
209                         "Unsupported advice type on method " + candidateAdviceMethod);
210         }
211
212         // Now to configure the advice...
213
springAdvice.setAspectName(aspectName);
214         springAdvice.setDeclarationOrder(declarationOrderInAspect);
215         String JavaDoc[] argNames = getArgumentNames(candidateAdviceMethod);
216         if (argNames != null) {
217             springAdvice.setArgumentNamesFromStringArray(argNames);
218         }
219         try {
220             springAdvice.afterPropertiesSet();
221         }
222         catch (Exception JavaDoc ex) {
223             throw new IllegalArgumentException JavaDoc("Advice configuration failed", ex);
224         }
225         return (Advice) springAdvice;
226     }
227
228     private String JavaDoc[] getArgumentNames(Method JavaDoc forMethod) {
229         String JavaDoc[] argNames = this.parameterNameDiscoverer.getParameterNames(forMethod);
230         if (argNames != null) {
231             if (forMethod.getParameterTypes().length == argNames.length + 1) {
232                 // May need to add implicit join point arg name...
233
Class JavaDoc firstArgType = forMethod.getParameterTypes()[0];
234                 if (firstArgType == JoinPoint.class ||
235                         firstArgType == ProceedingJoinPoint.class ||
236                         firstArgType == JoinPoint.StaticPart.class) {
237                     String JavaDoc[] oldNames = argNames;
238                     argNames = new String JavaDoc[oldNames.length + 1];
239                     argNames[0] = "THIS_JOIN_POINT";
240                     System.arraycopy(oldNames, 0, argNames, 1, oldNames.length);
241                 }
242             }
243         }
244         return argNames;
245     }
246
247
248     /**
249      * Synthetic advisor that instantiates the aspect.
250      * Triggered by per-clause pointcut on non-singleton aspect.
251      * The advice has no effect.
252      */

253     protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
254
255         public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
256             super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
257                 public void before(Method JavaDoc method, Object JavaDoc[] args, Object JavaDoc target) {
258                     // Simply instantiate the aspect
259
aif.getAspectInstance();
260                 }
261             });
262         }
263     }
264
265 }
266
Popular Tags