001: /*
002: * Copyright 2002-2007 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.framework;
018:
019: import java.io.IOException;
020: import java.io.ObjectInputStream;
021:
022: import org.springframework.aop.TargetSource;
023: import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
024: import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
025: import org.springframework.aop.target.SingletonTargetSource;
026: import org.springframework.beans.factory.BeanClassLoaderAware;
027: import org.springframework.beans.factory.FactoryBean;
028: import org.springframework.beans.factory.FactoryBeanNotInitializedException;
029: import org.springframework.beans.factory.InitializingBean;
030: import org.springframework.util.ClassUtils;
031:
032: /**
033: * Convenient proxy factory bean superclass for proxy factory
034: * beans that create only singletons.
035: *
036: * <p>Manages pre- and post-interceptors (references, rather than
037: * interceptor names, as in {@link ProxyFactoryBean}) and provides
038: * consistent interface management.
039: *
040: * @author Juergen Hoeller
041: * @since 2.0
042: */
043: public abstract class AbstractSingletonProxyFactoryBean extends
044: ProxyConfig implements FactoryBean, BeanClassLoaderAware,
045: InitializingBean {
046:
047: private Object target;
048:
049: private Class[] proxyInterfaces;
050:
051: private Object[] preInterceptors;
052:
053: private Object[] postInterceptors;
054:
055: /** Default is global AdvisorAdapterRegistry */
056: private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry
057: .getInstance();
058:
059: private transient ClassLoader beanClassLoader = ClassUtils
060: .getDefaultClassLoader();
061:
062: private Object proxy;
063:
064: /**
065: * Set the target object, that is, the bean to be wrapped with a transactional proxy.
066: * <p>The target may be any object, in which case a SingletonTargetSource will
067: * be created. If it is a TargetSource, no wrapper TargetSource is created:
068: * This enables the use of a pooling or prototype TargetSource etc.
069: * @see org.springframework.aop.TargetSource
070: * @see org.springframework.aop.target.SingletonTargetSource
071: * @see org.springframework.aop.target.LazyInitTargetSource
072: * @see org.springframework.aop.target.PrototypeTargetSource
073: * @see org.springframework.aop.target.CommonsPoolTargetSource
074: */
075: public void setTarget(Object target) {
076: this .target = target;
077: }
078:
079: /**
080: * Specify the set of interfaces being proxied.
081: * <p>If not specified (the default), the AOP infrastructure works
082: * out which interfaces need proxying by analyzing the target,
083: * proxying all the interfaces that the target object implements.
084: */
085: public void setProxyInterfaces(Class[] proxyInterfaces) {
086: this .proxyInterfaces = proxyInterfaces;
087: }
088:
089: /**
090: * Set additional interceptors (or advisors) to be applied before the
091: * implicit transaction interceptor, e.g. PerformanceMonitorInterceptor.
092: * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor
093: */
094: public void setPreInterceptors(Object[] preInterceptors) {
095: this .preInterceptors = preInterceptors;
096: }
097:
098: /**
099: * Set additional interceptors (or advisors) to be applied after the
100: * implicit transaction interceptor, e.g. HibernateInterceptors for
101: * eagerly binding Sessions to the current thread when using JTA.
102: * <p>Note that this is just necessary if you rely on those interceptors in general:
103: * HibernateTemplate and JdoTemplate work nicely with JtaTransactionManager through
104: * implicit on-demand thread binding.
105: * @see org.springframework.orm.hibernate3.HibernateInterceptor
106: * @see org.springframework.orm.jdo.JdoInterceptor
107: */
108: public void setPostInterceptors(Object[] postInterceptors) {
109: this .postInterceptors = postInterceptors;
110: }
111:
112: /**
113: * Specify the AdvisorAdapterRegistry to use.
114: * Default is the global AdvisorAdapterRegistry.
115: * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
116: */
117: public void setAdvisorAdapterRegistry(
118: AdvisorAdapterRegistry advisorAdapterRegistry) {
119: this .advisorAdapterRegistry = advisorAdapterRegistry;
120: }
121:
122: public void setBeanClassLoader(ClassLoader classLoader) {
123: this .beanClassLoader = classLoader;
124: }
125:
126: public void afterPropertiesSet() {
127: if (this .target == null) {
128: throw new IllegalArgumentException(
129: "Property 'target' is required");
130: }
131: if (this .target instanceof String) {
132: throw new IllegalArgumentException(
133: "'target' needs to be a bean reference, not a bean name as value");
134: }
135:
136: ProxyFactory proxyFactory = new ProxyFactory();
137:
138: if (this .preInterceptors != null) {
139: for (int i = 0; i < this .preInterceptors.length; i++) {
140: proxyFactory.addAdvisor(this .advisorAdapterRegistry
141: .wrap(this .preInterceptors[i]));
142: }
143: }
144:
145: // Add the main interceptor (typically an Advisor).
146: proxyFactory.addAdvisor(this .advisorAdapterRegistry
147: .wrap(createMainInterceptor()));
148:
149: if (this .postInterceptors != null) {
150: for (int i = 0; i < this .postInterceptors.length; i++) {
151: proxyFactory.addAdvisor(this .advisorAdapterRegistry
152: .wrap(this .postInterceptors[i]));
153: }
154: }
155:
156: proxyFactory.copyFrom(this );
157:
158: TargetSource targetSource = createTargetSource(this .target);
159: proxyFactory.setTargetSource(targetSource);
160:
161: if (this .proxyInterfaces != null) {
162: proxyFactory.setInterfaces(this .proxyInterfaces);
163: } else if (!isProxyTargetClass()) {
164: // Rely on AOP infrastructure to tell us what interfaces to proxy.
165: proxyFactory.setInterfaces(ClassUtils
166: .getAllInterfacesForClass(targetSource
167: .getTargetClass()));
168: }
169:
170: this .proxy = getProxy(proxyFactory);
171: }
172:
173: /**
174: * Determine a TargetSource for the given target (or TargetSource).
175: * @param target target. If this is an implementation of TargetSource it is
176: * used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource.
177: * @return a TargetSource for this object
178: */
179: protected TargetSource createTargetSource(Object target) {
180: if (target instanceof TargetSource) {
181: return (TargetSource) target;
182: } else {
183: return new SingletonTargetSource(target);
184: }
185: }
186:
187: /**
188: * Return the proxy object to expose.
189: * <p>The default implementation uses a <code>getProxy</code> call with
190: * the factory's bean class loader. Can be overridden to specify a
191: * custom class loader.
192: * @param aopProxy the prepared AopProxy instance to get the proxy from
193: * @return the proxy object to expose
194: * @see AopProxy#getProxy(ClassLoader)
195: */
196: protected Object getProxy(AopProxy aopProxy) {
197: return aopProxy.getProxy(this .beanClassLoader);
198: }
199:
200: public Object getObject() {
201: if (this .proxy == null) {
202: throw new FactoryBeanNotInitializedException();
203: }
204: return this .proxy;
205: }
206:
207: public Class getObjectType() {
208: if (this .proxy != null) {
209: return this .proxy.getClass();
210: }
211: if (this .proxyInterfaces != null
212: && this .proxyInterfaces.length == 1) {
213: return this .proxyInterfaces[0];
214: }
215: if (this .target instanceof TargetSource) {
216: return ((TargetSource) this .target).getTargetClass();
217: }
218: if (this .target != null) {
219: return this .target.getClass();
220: }
221: return null;
222: }
223:
224: public final boolean isSingleton() {
225: return true;
226: }
227:
228: /**
229: * Create the "main" interceptor for this proxy factory bean.
230: * Typically an Advisor, but can also be any type of Advice.
231: * <p>Pre-interceptors will be applied before, post-interceptors
232: * will be applied after this interceptor.
233: */
234: protected abstract Object createMainInterceptor();
235:
236: }
|