KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.HashMap JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import org.aspectj.lang.reflect.PerClauseKind;
24
25 import org.springframework.aop.Advisor;
26 import org.springframework.aop.aspectj.AspectJProxyUtils;
27 import org.springframework.aop.framework.ProxyCreatorSupport;
28 import org.springframework.beans.BeanUtils;
29 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
30 import org.springframework.beans.factory.support.RootBeanDefinition;
31 import org.springframework.util.Assert;
32 import org.springframework.util.ClassUtils;
33
34 /**
35  * AspectJ-based proxy factory, allowing for programmatic building
36  * of proxies which include AspectJ aspects (code style as well
37  * Java 5 annotation style).
38  *
39  * @author Rob Harrop
40  * @author Juergen Hoeller
41  * @since 2.0
42  * @see #addAspect(Object)
43  * @see #addAspect(Class)
44  * @see #getProxy()
45  * @see #getProxy(ClassLoader)
46  * @see org.springframework.aop.framework.ProxyFactory
47  */

48 public class AspectJProxyFactory extends ProxyCreatorSupport {
49
50     /** Cache for singleton aspect instances */
51     private static final Map JavaDoc aspectCache = new HashMap JavaDoc();
52
53     private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
54
55
56     /**
57      * Create a new AspectJProxyFactory.
58      */

59     public AspectJProxyFactory() {
60     }
61
62     /**
63      * Create a new AspectJProxyFactory.
64      * <p>Will proxy all interfaces that the given target implements.
65      * @param target the target object to be proxied
66      */

67     public AspectJProxyFactory(Object JavaDoc target) {
68         Assert.notNull(target, "Target object must not be null");
69         setInterfaces(ClassUtils.getAllInterfaces(target));
70         setTarget(target);
71     }
72
73     /**
74      * Create a new <code>AspectJProxyFactory</code>.
75      * No target, only interfaces. Must add interceptors.
76      */

77     public AspectJProxyFactory(Class JavaDoc[] interfaces) {
78         setInterfaces(interfaces);
79     }
80
81
82     /**
83      * Add the supplied aspect instance to the chain. The type of the aspect instance
84      * supplied must be a singleton aspect. True singleton lifecycle is not honoured when
85      * using this method - the caller is responsible for managing the lifecycle of any
86      * aspects added in this way.
87      */

88     public void addAspect(Object JavaDoc aspect) {
89         Class JavaDoc aspectType = aspect.getClass();
90         String JavaDoc beanName = aspectType.getName();
91         AspectMetadata am = createAspectMetadata(aspectType, beanName);
92         if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
93             throw new IllegalArgumentException JavaDoc("Aspect type '" + aspectType.getName() + "' is not a singleton aspect.");
94         }
95         MetadataAwareAspectInstanceFactory instanceFactory =
96                 new SingletonMetadataAwareAspectInstanceFactory(aspect, beanName);
97         addAdvisorsFromAspectInstanceFactory(instanceFactory);
98     }
99
100     /**
101      * Add an aspect of the supplied type to the end of the advice chain.
102      */

103     public void addAspect(Class JavaDoc aspectType) {
104         String JavaDoc beanName = aspectType.getName();
105         AspectMetadata am = createAspectMetadata(aspectType, beanName);
106         MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectType, beanName);
107         addAdvisorsFromAspectInstanceFactory(instanceFactory);
108     }
109
110     /**
111      * Add all {@link Advisor Advisors} from the supplied {@link MetadataAwareAspectInstanceFactory}
112      * to the current chain. Exposes any special purpose {@link Advisor Advisors} if needed.
113      * @see #makeAdvisorChainAspectJCapableIfNecessary()
114      */

115     private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
116         List JavaDoc advisors = this.aspectFactory.getAdvisors(instanceFactory);
117         this.addAllAdvisors((Advisor[]) advisors.toArray(new Advisor[advisors.size()]));
118         makeAdvisorChainAspectJCapableIfNecessary();
119     }
120
121     /**
122      * Create an {@link AspectMetadata} instance for the supplied aspect type.
123      */

124     private AspectMetadata createAspectMetadata(Class JavaDoc aspectType, String JavaDoc beanName) {
125         AspectMetadata am = new AspectMetadata(aspectType, beanName);
126         if (!am.getAjType().isAspect()) {
127             throw new IllegalArgumentException JavaDoc("Class [" + aspectType.getName() + "] is not a valid aspect type");
128         }
129         return am;
130     }
131
132     /**
133      * Create a {@link MetadataAwareAspectInstanceFactory} for the supplied aspect type. If the aspect type
134      * has no per clause, then a {@link SingletonMetadataAwareAspectInstanceFactory} is returned, otherwise
135      * a {@link PrototypeAspectInstanceFactory} is returned.
136      */

137     private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(AspectMetadata am, Class JavaDoc aspectType, String JavaDoc beanName) {
138         MetadataAwareAspectInstanceFactory instanceFactory = null;
139         if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
140             Object JavaDoc instance = getSingletonAspectInstance(aspectType);
141             instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, beanName);
142         }
143         else {
144             // create BeanFactory for this aspect
145
DefaultListableBeanFactory bf = getPrototypeAspectBeanFactory(aspectType, beanName);
146             instanceFactory = new PrototypeAspectInstanceFactory(bf, beanName);
147         }
148         return instanceFactory;
149     }
150
151     /**
152      * Add any special-purpose {@link Advisor Advisors} needed for AspectJ support
153      * to the chain. {@link #updateAdvisorArray() Updates} the {@link Advisor} array
154      * and fires {@link #adviceChanged events}.
155      */

156     private void makeAdvisorChainAspectJCapableIfNecessary() {
157         if (AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(getAdvisorsInternal())) {
158             updateAdvisorArray();
159             adviceChanged();
160         }
161     }
162
163     /**
164      * Create a {@link DefaultListableBeanFactory} used to create prototype instances
165      * of the supplied aspect type.
166      */

167     private DefaultListableBeanFactory getPrototypeAspectBeanFactory(Class JavaDoc aspectType, String JavaDoc beanName) {
168         DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
169         RootBeanDefinition definition = new RootBeanDefinition(aspectType);
170         definition.setSingleton(false);
171         bf.registerBeanDefinition(beanName, definition);
172         return bf;
173     }
174
175     /**
176      * Get the singleton aspect instance for the supplied aspect type. An instance
177      * is created if one cannot be found in the instance cache.
178      */

179     private Object JavaDoc getSingletonAspectInstance(Class JavaDoc aspectType) {
180         synchronized (aspectCache) {
181             Object JavaDoc instance = aspectCache.get(aspectType);
182             if (instance != null) {
183                 return instance;
184             }
185             instance = BeanUtils.instantiateClass(aspectType);
186             aspectCache.put(aspectType, instance);
187             return instance;
188         }
189     }
190
191
192     /**
193      * Create a new proxy according to the settings in this factory.
194      * <p>Can be called repeatedly. Effect will vary if we've added
195      * or removed interfaces. Can add and remove interceptors.
196      * <p>Uses a default class loader: Usually, the thread context class loader
197      * (if necessary for proxy creation).
198      * @return the new proxy
199      */

200     public <T> T getProxy() {
201         return (T) createAopProxy().getProxy();
202     }
203
204     /**
205      * Create a new proxy according to the settings in this factory.
206      * <p>Can be called repeatedly. Effect will vary if we've added
207      * or removed interfaces. Can add and remove interceptors.
208      * <p>Uses the given class loader (if necessary for proxy creation).
209      * @param classLoader the class loader to create the proxy with
210      * @return the new proxy
211      */

212     public <T> T getProxy(ClassLoader JavaDoc classLoader) {
213         return (T) createAopProxy().getProxy(classLoader);
214     }
215
216 }
217
Popular Tags