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.beans.factory.config;
018:
019: import java.lang.reflect.InvocationHandler;
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022: import java.lang.reflect.Proxy;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import org.springframework.beans.SimpleTypeConverter;
028: import org.springframework.beans.TypeConverter;
029: import org.springframework.beans.factory.BeanFactory;
030: import org.springframework.beans.factory.BeanFactoryAware;
031: import org.springframework.beans.factory.DisposableBean;
032: import org.springframework.beans.factory.FactoryBean;
033: import org.springframework.beans.factory.FactoryBeanNotInitializedException;
034: import org.springframework.beans.factory.InitializingBean;
035:
036: /**
037: * Simple template superclass for {@link FactoryBean} implementations that
038: * creates a singleton or a prototype object, depending on a flag.
039: *
040: * <p>If the "singleton" flag is <code>true</code> (the default),
041: * this class will create the object that it creates exactly once
042: * on initialization and subsequently return said singleton instance
043: * on all calls to the {@link #getObject()} method.
044: *
045: * <p>Else, this class will create a new instance every time the
046: * {@link #getObject()} method is invoked. Subclasses are responsible
047: * for implementing the abstract {@link #createInstance()} template
048: * method to actually create the object(s) to expose.
049: *
050: * @author Juergen Hoeller
051: * @author Keith Donald
052: * @since 1.0.2
053: * @see #setSingleton(boolean)
054: * @see #createInstance()
055: */
056: public abstract class AbstractFactoryBean implements FactoryBean,
057: BeanFactoryAware, InitializingBean, DisposableBean {
058:
059: /** Logger available to subclasses */
060: protected final Log logger = LogFactory.getLog(getClass());
061:
062: private boolean singleton = true;
063:
064: private BeanFactory beanFactory;
065:
066: private boolean initialized = false;
067:
068: private Object singletonInstance;
069:
070: private Object earlySingletonInstance;
071:
072: /**
073: * Set if a singleton should be created, or a new object
074: * on each request else. Default is <code>true</code> (a singleton).
075: */
076: public void setSingleton(boolean singleton) {
077: this .singleton = singleton;
078: }
079:
080: public boolean isSingleton() {
081: return this .singleton;
082: }
083:
084: public void setBeanFactory(BeanFactory beanFactory) {
085: this .beanFactory = beanFactory;
086: }
087:
088: /**
089: * Return the BeanFactory that this bean runs in.
090: */
091: protected BeanFactory getBeanFactory() {
092: return this .beanFactory;
093: }
094:
095: /**
096: * Obtain a bean type converter from the BeanFactory that this bean
097: * runs in. This is typically a fresh instance for each call,
098: * since TypeConverters are usually <i>not</i> thread-safe.
099: * <p>Falls back to a SimpleTypeConverter when not running in a BeanFactory.
100: * @see ConfigurableBeanFactory#getTypeConverter()
101: * @see org.springframework.beans.SimpleTypeConverter
102: */
103: protected TypeConverter getBeanTypeConverter() {
104: BeanFactory beanFactory = getBeanFactory();
105: if (beanFactory instanceof ConfigurableBeanFactory) {
106: return ((ConfigurableBeanFactory) beanFactory)
107: .getTypeConverter();
108: } else {
109: return new SimpleTypeConverter();
110: }
111: }
112:
113: /**
114: * Eagerly create the singleton instance, if necessary.
115: */
116: public void afterPropertiesSet() throws Exception {
117: if (isSingleton()) {
118: this .initialized = true;
119: this .singletonInstance = createInstance();
120: this .earlySingletonInstance = null;
121: }
122: }
123:
124: /**
125: * Expose the singleton instance or create a new prototype instance.
126: * @see #createInstance()
127: * @see #getEarlySingletonInterfaces()
128: */
129: public final Object getObject() throws Exception {
130: if (isSingleton()) {
131: return (this .initialized ? this .singletonInstance
132: : getEarlySingletonInstance());
133: } else {
134: return createInstance();
135: }
136: }
137:
138: /**
139: * Determine an 'eager singleton' instance, exposed in case of a
140: * circular reference. Not called in a non-circular scenario.
141: */
142: private Object getEarlySingletonInstance() throws Exception {
143: Class[] ifcs = getEarlySingletonInterfaces();
144: if (ifcs == null) {
145: throw new FactoryBeanNotInitializedException(getClass()
146: .getName()
147: + " does not support circular references");
148: }
149: if (this .earlySingletonInstance == null) {
150: this .earlySingletonInstance = Proxy.newProxyInstance(
151: getClass().getClassLoader(), ifcs,
152: new InvocationHandler() {
153: public Object invoke(Object proxy,
154: Method method, Object[] args)
155: throws Throwable {
156: try {
157: return method.invoke(
158: getSingletonInstance(), args);
159: } catch (InvocationTargetException ex) {
160: throw ex.getTargetException();
161: }
162: }
163: });
164: }
165: return this .earlySingletonInstance;
166: }
167:
168: /**
169: * Expose the singleton instance (for access through the 'early singleton' proxy).
170: * @return the singleton instance that this FactoryBean holds
171: * @throws IllegalStateException if the singleton instance is not initialized
172: */
173: private Object getSingletonInstance() throws IllegalStateException {
174: if (!this .initialized) {
175: throw new IllegalStateException(
176: "Singleton instance not initialized yet");
177: }
178: return this .singletonInstance;
179: }
180:
181: /**
182: * Destroy the singleton instance, if any.
183: * @see #destroyInstance(Object)
184: */
185: public void destroy() throws Exception {
186: if (isSingleton()) {
187: destroyInstance(this .singletonInstance);
188: }
189: }
190:
191: /**
192: * This abstract method declaration mirrors the method in the FactoryBean
193: * interface, for a consistent offering of abstract template methods.
194: * @see org.springframework.beans.factory.FactoryBean#getObjectType()
195: */
196: public abstract Class getObjectType();
197:
198: /**
199: * Template method that subclasses must override to construct
200: * the object returned by this factory.
201: * <p>Invoked on initialization of this FactoryBean in case of
202: * a singleton; else, on each {@link #getObject()} call.
203: * @return the object returned by this factory
204: * @throws Exception if an exception occured during object creation
205: * @see #getObject()
206: */
207: protected abstract Object createInstance() throws Exception;
208:
209: /**
210: * Return an array of interfaces that a singleton object exposed by this
211: * FactoryBean is supposed to implement, for use with an 'early singleton
212: * proxy' that will be exposed in case of a circular reference.
213: * <p>The default implementation returns this FactoryBean's object type,
214: * provided that it is an interface, or <code>null</code> else. The latter
215: * indicates that early singleton access is not supported by this FactoryBean.
216: * This will lead to a FactoryBeanNotInitializedException getting thrown.
217: * @return the interfaces to use for 'early singletons',
218: * or <code>null</code> to indicate a FactoryBeanNotInitializedException
219: * @see org.springframework.beans.factory.FactoryBeanNotInitializedException
220: */
221: protected Class[] getEarlySingletonInterfaces() {
222: Class type = getObjectType();
223: return (type != null && type.isInterface() ? new Class[] { type }
224: : 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 instance) throws Exception {
237: }
238:
239: }
|