001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.aop.aspectj.annotation;
018:
019: import java.lang.reflect.Method;
020:
021: import org.aopalliance.aop.Advice;
022: import org.aspectj.lang.reflect.PerClauseKind;
023:
024: import org.springframework.aop.Pointcut;
025: import org.springframework.aop.aspectj.AspectJExpressionPointcut;
026: import org.springframework.aop.aspectj.AspectJPrecedenceInformation;
027: import org.springframework.aop.aspectj.InstantiationModelAwarePointcutAdvisor;
028: import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotation;
029: import org.springframework.aop.support.DynamicMethodMatcherPointcut;
030: import org.springframework.aop.support.Pointcuts;
031:
032: /**
033: * Internal implementation of AspectJPointcutAdvisor.
034: * Note that there will be one instance of this advisor for each target method.
035: *
036: * @author Rod Johnson
037: * @author Juergen Hoeller
038: * @since 2.0
039: */
040: class InstantiationModelAwarePointcutAdvisorImpl implements
041: InstantiationModelAwarePointcutAdvisor,
042: AspectJPrecedenceInformation {
043:
044: private final AspectJExpressionPointcut declaredPointcut;
045:
046: private Pointcut pointcut;
047:
048: private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
049:
050: private final Method method;
051:
052: private final boolean lazy;
053:
054: private final AspectJAdvisorFactory atAspectJAdvisorFactory;
055:
056: private Advice instantiatedAdvice;
057:
058: private int declarationOrder;
059:
060: private String aspectName;
061:
062: private Boolean isBeforeAdvice = null;
063:
064: private Boolean isAfterAdvice = null;
065:
066: public InstantiationModelAwarePointcutAdvisorImpl(
067: AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
068: MetadataAwareAspectInstanceFactory aif, Method method,
069: int declarationOrderInAspect, String aspectName) {
070:
071: this .declaredPointcut = ajexp;
072: this .method = method;
073: this .atAspectJAdvisorFactory = af;
074: this .aspectInstanceFactory = aif;
075: this .declarationOrder = declarationOrderInAspect;
076: this .aspectName = aspectName;
077:
078: if (aif.getAspectMetadata().isLazilyInstantiated()) {
079: // Static part of the pointcut is a lazy type.
080: Pointcut preInstantiationPointcut = Pointcuts.union(aif
081: .getAspectMetadata().getPerClausePointcut(),
082: this .declaredPointcut);
083:
084: // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
085: // If it's not a dynamic pointcut, it may be optimized out
086: // by the Spring AOP infrastructure after the first evaluation.
087: this .pointcut = new PerTargetInstantiationModelPointcut(
088: this .declaredPointcut, preInstantiationPointcut,
089: aif);
090: this .lazy = true;
091: } else {
092: // A singleton aspect.
093: this .instantiatedAdvice = instantiateAdvice(this .declaredPointcut);
094: this .pointcut = declaredPointcut;
095: this .lazy = false;
096: }
097: }
098:
099: /**
100: * The pointcut for Spring AOP to use. Actual behaviour of the pointcut will change
101: * depending on the state of the advice.
102: */
103: public Pointcut getPointcut() {
104: return this .pointcut;
105: }
106:
107: /**
108: * This is only of interest for Spring AOP: AspectJ instantiation semantics
109: * are much richer. In AspectJ terminology, all a return of <code>true</code>
110: * means here is that the aspect is not a SINGLETON.
111: */
112: public boolean isPerInstance() {
113: return (getAspectMetadata().getAjType().getPerClause()
114: .getKind() != PerClauseKind.SINGLETON);
115: }
116:
117: /**
118: * Return the AspectJ AspectMetadata for this advisor.
119: */
120: public AspectMetadata getAspectMetadata() {
121: return this .aspectInstanceFactory.getAspectMetadata();
122: }
123:
124: /**
125: * Lazily instantiate advice if necessary.
126: */
127: public synchronized Advice getAdvice() {
128: if (this .instantiatedAdvice == null) {
129: this .instantiatedAdvice = instantiateAdvice(this .declaredPointcut);
130: }
131: return this .instantiatedAdvice;
132: }
133:
134: public boolean isLazy() {
135: return this .lazy;
136: }
137:
138: public synchronized boolean isAdviceInstantiated() {
139: return (this .instantiatedAdvice != null);
140: }
141:
142: private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
143: return this .atAspectJAdvisorFactory.getAdvice(this .method,
144: pcut, this .aspectInstanceFactory,
145: this .declarationOrder, this .aspectName);
146: }
147:
148: public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() {
149: return this .aspectInstanceFactory;
150: }
151:
152: public AspectJExpressionPointcut getDeclaredPointcut() {
153: return this .declaredPointcut;
154: }
155:
156: public int getOrder() {
157: return this .aspectInstanceFactory.getOrder();
158: }
159:
160: public String getAspectName() {
161: return this .aspectName;
162: }
163:
164: public int getDeclarationOrder() {
165: return this .declarationOrder;
166: }
167:
168: public boolean isBeforeAdvice() {
169: if (this .isBeforeAdvice == null) {
170: determineAdviceType();
171: }
172: return this .isBeforeAdvice;
173: }
174:
175: public boolean isAfterAdvice() {
176: if (this .isAfterAdvice == null) {
177: determineAdviceType();
178: }
179: return this .isAfterAdvice;
180: }
181:
182: /**
183: * Duplicates some logic from getAdvice, but importantly does not force
184: * creation of the advice.
185: */
186: private void determineAdviceType() {
187: AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory
188: .findAspectJAnnotationOnMethod(this .method);
189: if (aspectJAnnotation == null) {
190: this .isBeforeAdvice = false;
191: this .isAfterAdvice = false;
192: } else {
193: switch (aspectJAnnotation.getAnnotationType()) {
194: case AtAfter:
195: case AtAfterReturning:
196: case AtAfterThrowing:
197: this .isAfterAdvice = true;
198: this .isBeforeAdvice = false;
199: break;
200: case AtAround:
201: case AtPointcut:
202: this .isAfterAdvice = false;
203: this .isBeforeAdvice = false;
204: break;
205: case AtBefore:
206: this .isAfterAdvice = false;
207: this .isBeforeAdvice = true;
208: }
209: }
210: }
211:
212: @Override
213: public String toString() {
214: return "InstantiationModelAwarePointcutAdvisor: expression ["
215: + getDeclaredPointcut().getExpression()
216: + "]; advice method ["
217: + this .method
218: + "]; perClauseKind="
219: + this .aspectInstanceFactory.getAspectMetadata()
220: .getAjType().getPerClause().getKind();
221:
222: }
223:
224: /**
225: * Pointcut implementation that changes its behaviour when the advice is instantiated.
226: * Note that this is a <i>dynamic</i> pointcut. Otherwise it might
227: * be optimized out if it does not at first match statically.
228: */
229: private class PerTargetInstantiationModelPointcut extends
230: DynamicMethodMatcherPointcut {
231:
232: private final AspectJExpressionPointcut declaredPointcut;
233:
234: private final Pointcut preInstantiationPointcut;
235:
236: private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory;
237:
238: private PerTargetInstantiationModelPointcut(
239: AspectJExpressionPointcut declaredPointcut,
240: Pointcut preInstantiationPointcut,
241: MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
242: this .declaredPointcut = declaredPointcut;
243: this .preInstantiationPointcut = preInstantiationPointcut;
244: if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) {
245: this .aspectInstanceFactory = (LazySingletonAspectInstanceFactoryDecorator) aspectInstanceFactory;
246: }
247: }
248:
249: @Override
250: public boolean matches(Method method, Class targetClass) {
251: // We're either instantiated and matching on declared pointcut, or uninstantiated matching on either pointcut
252: return (isAspectMaterialized() && this .declaredPointcut
253: .matches(method, targetClass))
254: || this .preInstantiationPointcut.getMethodMatcher()
255: .matches(method, targetClass);
256: }
257:
258: public boolean matches(Method method, Class targetClass,
259: Object[] args) {
260: // This can match only on declared pointcut.
261: return (isAspectMaterialized() && this .declaredPointcut
262: .matches(method, targetClass));
263: }
264:
265: private boolean isAspectMaterialized() {
266: return (this.aspectInstanceFactory == null || this.aspectInstanceFactory
267: .isMaterialized());
268: }
269: }
270:
271: }
|