KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > config > AbstractFactoryBean


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.beans.factory.config;
18
19 import java.lang.reflect.InvocationHandler JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Proxy JavaDoc;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import org.springframework.beans.SimpleTypeConverter;
28 import org.springframework.beans.TypeConverter;
29 import org.springframework.beans.factory.BeanFactory;
30 import org.springframework.beans.factory.BeanFactoryAware;
31 import org.springframework.beans.factory.DisposableBean;
32 import org.springframework.beans.factory.FactoryBean;
33 import org.springframework.beans.factory.FactoryBeanNotInitializedException;
34 import org.springframework.beans.factory.InitializingBean;
35
36 /**
37  * Simple template superclass for {@link FactoryBean} implementations that
38  * creates a singleton or a prototype object, depending on a flag.
39  *
40  * <p>If the "singleton" flag is <code>true</code> (the default),
41  * this class will create the object that it creates exactly once
42  * on initialization and subsequently return said singleton instance
43  * on all calls to the {@link #getObject()} method.
44  *
45  * <p>Else, this class will create a new instance every time the
46  * {@link #getObject()} method is invoked. Subclasses are responsible
47  * for implementing the abstract {@link #createInstance()} template
48  * method to actually create the object(s) to expose.
49  *
50  * @author Juergen Hoeller
51  * @author Keith Donald
52  * @since 1.0.2
53  * @see #setSingleton(boolean)
54  * @see #createInstance()
55  */

56 public abstract class AbstractFactoryBean
57         implements FactoryBean, BeanFactoryAware, InitializingBean, DisposableBean {
58
59     /** Logger available to subclasses */
60     protected final Log logger = LogFactory.getLog(getClass());
61
62     private boolean singleton = true;
63
64     private BeanFactory beanFactory;
65
66     private boolean initialized = false;
67
68     private Object JavaDoc singletonInstance;
69
70     private Object JavaDoc earlySingletonInstance;
71
72
73     /**
74      * Set if a singleton should be created, or a new object
75      * on each request else. Default is <code>true</code> (a singleton).
76      */

77     public void setSingleton(boolean singleton) {
78         this.singleton = singleton;
79     }
80
81     public boolean isSingleton() {
82         return this.singleton;
83     }
84
85     public void setBeanFactory(BeanFactory beanFactory) {
86         this.beanFactory = beanFactory;
87     }
88
89     /**
90      * Return the BeanFactory that this bean runs in.
91      */

92     protected BeanFactory getBeanFactory() {
93         return this.beanFactory;
94     }
95
96     /**
97      * Obtain a bean type converter from the BeanFactory that this bean
98      * runs in. This is typically a fresh instance for each call,
99      * since TypeConverters are usually <i>not</i> thread-safe.
100      * <p>Falls back to a SimpleTypeConverter when not running in a BeanFactory.
101      * @see ConfigurableBeanFactory#getTypeConverter()
102      * @see org.springframework.beans.SimpleTypeConverter
103      */

104     protected TypeConverter getBeanTypeConverter() {
105         BeanFactory beanFactory = getBeanFactory();
106         if (beanFactory instanceof ConfigurableBeanFactory) {
107             return ((ConfigurableBeanFactory) beanFactory).getTypeConverter();
108         }
109         else {
110             return new SimpleTypeConverter();
111         }
112     }
113
114     /**
115      * Eagerly create the singleton instance, if necessary.
116      */

117     public void afterPropertiesSet() throws Exception JavaDoc {
118         if (isSingleton()) {
119             this.initialized = true;
120             this.singletonInstance = createInstance();
121             this.earlySingletonInstance = null;
122         }
123     }
124
125
126     /**
127      * Expose the singleton instance or create a new prototype instance.
128      * @see #createInstance()
129      * @see #getEarlySingletonInterfaces()
130      */

131     public final Object JavaDoc getObject() throws Exception JavaDoc {
132         if (isSingleton()) {
133             return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
134         }
135         else {
136             return createInstance();
137         }
138     }
139
140     /**
141      * Determine an 'eager singleton' instance, exposed in case of a
142      * circular reference. Not called in a non-circular scenario.
143      */

144     private Object JavaDoc getEarlySingletonInstance() throws Exception JavaDoc {
145         Class JavaDoc[] ifcs = getEarlySingletonInterfaces();
146         if (ifcs == null) {
147             throw new FactoryBeanNotInitializedException(
148                     getClass().getName() + " does not support circular references");
149         }
150         if (this.earlySingletonInstance == null) {
151             this.earlySingletonInstance = Proxy.newProxyInstance(getClass().getClassLoader(), ifcs,
152                 new InvocationHandler JavaDoc() {
153                     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
154                         try {
155                             return method.invoke(getSingletonInstance(), args);
156                         }
157                         catch (InvocationTargetException JavaDoc ex) {
158                             throw ex.getTargetException();
159                         }
160                     }
161                 });
162         }
163         return this.earlySingletonInstance;
164     }
165
166     /**
167      * Expose the singleton instance (for access through the 'early singleton' proxy).
168      * @return the singleton instance that this FactoryBean holds
169      * @throws IllegalStateException if the singleton instance is not initialized
170      */

171     private Object JavaDoc getSingletonInstance() throws IllegalStateException JavaDoc {
172         if (!this.initialized) {
173             throw new IllegalStateException JavaDoc("Singleton instance not initialized yet");
174         }
175         return this.singletonInstance;
176     }
177
178     /**
179      * Destroy the singleton instance, if any.
180      * @see #destroyInstance(Object)
181      */

182     public void destroy() throws Exception JavaDoc {
183         if (isSingleton()) {
184             destroyInstance(this.singletonInstance);
185         }
186     }
187
188
189     /**
190      * This abstract method declaration shadows the method in the FactoryBean interface.
191      * This is necessary to make the <code>getEarlySingletonInterfaces</code> implementation
192      * in this class work on Sun's JDK 1.3 classic VM, which can't find the method
193      * when executing <code>getEarlySingletonInterfaces</code> else.
194      * @see org.springframework.beans.factory.FactoryBean#getObjectType()
195      * @see #getEarlySingletonInterfaces()
196      */

197     public abstract Class JavaDoc getObjectType();
198
199     /**
200      * Template method that subclasses must override to construct
201      * the object returned by this factory.
202      * <p>Invoked on initialization of this FactoryBean in case of
203      * a singleton; else, on each {@link #getObject()} call.
204      * @return the object returned by this factory
205      * @throws Exception if an exception occured during object creation
206      * @see #getObject()
207      */

208     protected abstract Object JavaDoc createInstance() throws Exception JavaDoc;
209
210     /**
211      * Return an array of interfaces that a singleton object exposed by this
212      * FactoryBean is supposed to implement, for use with an 'early singleton
213      * proxy' that will be exposed in case of a circular reference.
214      * <p>The default implementation returns this FactoryBean's object type,
215      * provided that it is an interface, or <code>null</code> else. The latter
216      * indicates that early singleton access is not supported by this FactoryBean.
217      * This will lead to a FactoryBeanNotInitializedException getting thrown.
218      * @return the interfaces to use for 'early singletons',
219      * or <code>null</code> to indicate a FactoryBeanNotInitializedException
220      * @see org.springframework.beans.factory.FactoryBeanNotInitializedException
221      */

222     protected Class JavaDoc[] getEarlySingletonInterfaces() {
223         Class JavaDoc type = getObjectType();
224         return (type != null && type.isInterface() ? new Class JavaDoc[] {type} : null);
225     }
226
227     /**
228      * Callback for destroying a singleton instance. Subclasses may
229      * override this to destroy the previously created instance.
230      * <p>The default implementation is empty.
231      * @param instance the singleton instance, as returned by
232      * {@link #createInstance()}
233      * @throws Exception in case of shutdown errors
234      * @see #createInstance()
235      */

236     protected void destroyInstance(Object JavaDoc instance) throws Exception JavaDoc {
237     }
238
239 }
240
Popular Tags