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.scope;
018:
019: import java.lang.reflect.Modifier;
020:
021: import org.springframework.aop.framework.AopInfrastructureBean;
022: import org.springframework.aop.framework.ProxyConfig;
023: import org.springframework.aop.framework.ProxyFactory;
024: import org.springframework.aop.support.DelegatingIntroductionInterceptor;
025: import org.springframework.aop.target.SimpleBeanTargetSource;
026: import org.springframework.beans.factory.BeanFactory;
027: import org.springframework.beans.factory.BeanFactoryAware;
028: import org.springframework.beans.factory.FactoryBean;
029: import org.springframework.beans.factory.FactoryBeanNotInitializedException;
030: import org.springframework.beans.factory.config.ConfigurableBeanFactory;
031: import org.springframework.util.ClassUtils;
032:
033: /**
034: * Convenient proxy factory bean for scoped objects.
035: *
036: * <p>Proxies created using this factory bean are thread-safe singletons
037: * and may be injected into shared objects, with transparent scoping behavior.
038: *
039: * <p>Proxies returned by this class implement the {@link ScopedObject} interface.
040: * This presently allows for removing the corresponding object from the scope,
041: * seamlessly creating a new instance in the scope on next access.
042: *
043: * <p>Please note that the proxies created by this factory are
044: * <i>class-based</i> proxies by default. This can be customized
045: * through switching the "proxyTargetClass" property to "false".
046: *
047: * @author Rod Johnson
048: * @author Juergen Hoeller
049: * @since 2.0
050: * @see #setProxyTargetClass
051: */
052: public class ScopedProxyFactoryBean extends ProxyConfig implements
053: FactoryBean, BeanFactoryAware {
054:
055: /** The TargetSource that manages scoping */
056: private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
057:
058: /** The name of the target bean */
059: private String targetBeanName;
060:
061: /** The cached singleton proxy */
062: private Object proxy;
063:
064: /**
065: * Create a new ScopedProxyFactoryBean instance.
066: */
067: public ScopedProxyFactoryBean() {
068: setProxyTargetClass(true);
069: }
070:
071: /**
072: * Set the name of the bean that is to be scoped.
073: */
074: public void setTargetBeanName(String targetBeanName) {
075: this .targetBeanName = targetBeanName;
076: this .scopedTargetSource.setTargetBeanName(targetBeanName);
077: }
078:
079: public void setBeanFactory(BeanFactory beanFactory) {
080: if (!(beanFactory instanceof ConfigurableBeanFactory)) {
081: throw new IllegalStateException(
082: "Not running in a ConfigurableBeanFactory: "
083: + beanFactory);
084: }
085: ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
086:
087: this .scopedTargetSource.setBeanFactory(beanFactory);
088:
089: ProxyFactory pf = new ProxyFactory();
090: pf.copyFrom(this );
091: pf.setTargetSource(this .scopedTargetSource);
092:
093: Class beanType = beanFactory.getType(this .targetBeanName);
094: if (beanType == null) {
095: throw new IllegalStateException(
096: "Cannot create scoped proxy for bean '"
097: + this .targetBeanName
098: + "': Target type could not be determined at the time of proxy creation.");
099: }
100: if (!isProxyTargetClass() || beanType.isInterface()
101: || Modifier.isPrivate(beanType.getModifiers())) {
102: pf.setInterfaces(ClassUtils
103: .getAllInterfacesForClass(beanType));
104: }
105:
106: // Add an introduction that implements only the methods on ScopedObject.
107: ScopedObject scopedObject = new DefaultScopedObject(cbf,
108: this .scopedTargetSource.getTargetBeanName());
109: pf
110: .addAdvice(new DelegatingIntroductionInterceptor(
111: scopedObject));
112:
113: // Add the AopInfrastructureBean marker to indicate that the scoped proxy
114: // itself is not subject to auto-proxying! Only its target bean is.
115: pf.addInterface(AopInfrastructureBean.class);
116:
117: this .proxy = pf.getProxy(cbf.getBeanClassLoader());
118: }
119:
120: public Object getObject() {
121: if (this .proxy == null) {
122: throw new FactoryBeanNotInitializedException();
123: }
124: return this .proxy;
125: }
126:
127: public Class getObjectType() {
128: if (this .proxy != null) {
129: return this .proxy.getClass();
130: }
131: if (this .scopedTargetSource != null) {
132: return this .scopedTargetSource.getTargetClass();
133: }
134: return null;
135: }
136:
137: public boolean isSingleton() {
138: return true;
139: }
140:
141: }
|