KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > support > DisposableBeanAdapter


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.support;
18
19 import java.io.Serializable JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.springframework.beans.BeanUtils;
31 import org.springframework.beans.factory.DisposableBean;
32 import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
33 import org.springframework.util.Assert;
34
35 /**
36  * Adapter that implements the DisposableBean interface performing
37  * various destruction steps on a given bean instance:
38  * <ul>
39  * <li>DestructionAwareBeanPostProcessors
40  * <li>the bean implementing DisposableBean itself
41  * <li>a custom destroy method specified on the bean definition
42  * </ul>
43  *
44  * @author Juergen Hoeller
45  * @since 2.0
46  * @see AbstractBeanFactory
47  * @see org.springframework.beans.factory.DisposableBean
48  * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
49  * @see AbstractBeanDefinition#getDestroyMethodName()
50  */

51 class DisposableBeanAdapter implements DisposableBean, Runnable JavaDoc, Serializable JavaDoc {
52
53     private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
54
55     private final Object JavaDoc bean;
56
57     private final String JavaDoc beanName;
58
59     private final String JavaDoc destroyMethodName;
60
61     private final boolean enforceDestroyMethod;
62
63     private List JavaDoc beanPostProcessors;
64
65
66     /**
67      * Create a new DisposableBeanAdapter for the given bean.
68      * @param bean the bean instance (never <code>null</code>)
69      * @param beanName the name of the bean
70      * @param beanDefinition the merged bean definition, if any
71      * @param postProcessors the List of BeanPostProcessors
72      * (potentially DestructionAwareBeanPostProcessor), if any
73      */

74     public DisposableBeanAdapter(
75             Object JavaDoc bean, String JavaDoc beanName, RootBeanDefinition beanDefinition, List JavaDoc postProcessors) {
76
77         Assert.notNull(bean, "Bean must not be null");
78         this.bean = bean;
79         this.beanName = beanName;
80         this.destroyMethodName = beanDefinition.getDestroyMethodName();
81         this.enforceDestroyMethod = beanDefinition.isEnforceDestroyMethod();
82         this.beanPostProcessors = filterPostProcessors(postProcessors);
83     }
84
85     /**
86      * Create a new DisposableBeanAdapter for the given bean.
87      * @param bean the bean instance (never <code>null</code>)
88      * @param beanName the name of the bean
89      * @param destroyMethodName the name of the custom destroy method
90      * (<code>null</code> if there is none)
91      * @param enforceDestroyMethod whether to the specified custom
92      * destroy method (if any) has to be present on the bean object
93      * @param postProcessors the List of DestructionAwareBeanPostProcessors, if any
94      */

95     private DisposableBeanAdapter(
96             Object JavaDoc bean, String JavaDoc beanName, String JavaDoc destroyMethodName, boolean enforceDestroyMethod, List JavaDoc postProcessors) {
97
98         this.bean = bean;
99         this.beanName = beanName;
100         this.destroyMethodName = destroyMethodName;
101         this.enforceDestroyMethod = enforceDestroyMethod;
102         this.beanPostProcessors = postProcessors;
103     }
104
105     /**
106      * Search for all DestructionAwareBeanPostProcessors in the List.
107      * @param postProcessors the List to search
108      * @return the filtered List of DestructionAwareBeanPostProcessors
109      */

110     private List JavaDoc filterPostProcessors(List JavaDoc postProcessors) {
111         List JavaDoc filteredPostProcessors = null;
112         if (postProcessors != null && !postProcessors.isEmpty()) {
113             filteredPostProcessors = new ArrayList JavaDoc(postProcessors.size());
114             for (Iterator JavaDoc it = postProcessors.iterator(); it.hasNext();) {
115                 Object JavaDoc postProcessor = it.next();
116                 if (postProcessor instanceof DestructionAwareBeanPostProcessor) {
117                     filteredPostProcessors.add(postProcessor);
118                 }
119             }
120         }
121         return filteredPostProcessors;
122     }
123
124
125     public void run() {
126         destroy();
127     }
128
129     public void destroy() {
130         if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) {
131             if (logger.isTraceEnabled()) {
132                 logger.trace("Applying DestructionAwareBeanPostProcessors to bean with name '" + this.beanName + "'");
133             }
134             for (int i = this.beanPostProcessors.size() - 1; i >= 0; i--) {
135                 ((DestructionAwareBeanPostProcessor) this.beanPostProcessors.get(i)).postProcessBeforeDestruction(
136                         this.bean, this.beanName);
137             }
138         }
139
140         if (this.bean instanceof DisposableBean) {
141             if (logger.isDebugEnabled()) {
142                 logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
143             }
144             try {
145                 ((DisposableBean) this.bean).destroy();
146             }
147             catch (Throwable JavaDoc ex) {
148                 logger.error("Couldn't invoke destroy method of bean with name '" + this.beanName + "'", ex);
149             }
150         }
151
152         if (this.destroyMethodName != null) {
153             invokeCustomDestroyMethod();
154         }
155     }
156
157     /**
158      * Invoke the specified custom destroy method on the given bean.
159      * <p>This implementation invokes a no-arg method if found, else checking
160      * for a method with a single boolean argument (passing in "true",
161      * assuming a "force" parameter), else logging an error.
162      */

163     private void invokeCustomDestroyMethod() {
164         if (this.destroyMethodName != null) {
165             try {
166                 Method JavaDoc destroyMethod = BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), destroyMethodName);
167                 if (destroyMethod == null) {
168                     if (this.enforceDestroyMethod) {
169                         logger.error("Couldn't find a destroy method named '" + destroyMethodName +
170                                 "' on bean with name '" + this.beanName + "'");
171                     }
172                 }
173
174                 else {
175                     Class JavaDoc[] paramTypes = destroyMethod.getParameterTypes();
176                     if (paramTypes.length > 1) {
177                         logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName +
178                                 "' has more than one parameter - not supported as destroy method");
179                     }
180                     else if (paramTypes.length == 1 && !paramTypes[0].equals(boolean.class)) {
181                         logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName +
182                                 "' has a non-boolean parameter - not supported as destroy method");
183                     }
184
185                     else {
186                         Object JavaDoc[] args = new Object JavaDoc[paramTypes.length];
187                         if (paramTypes.length == 1) {
188                             args[0] = Boolean.TRUE;
189                         }
190                         if (!Modifier.isPublic(destroyMethod.getModifiers()) ||
191                                 !Modifier.isPublic(destroyMethod.getDeclaringClass().getModifiers())) {
192                             destroyMethod.setAccessible(true);
193                         }
194
195                         if (logger.isDebugEnabled()) {
196                             logger.debug("Invoking custom destroy method on bean with name '" + this.beanName + "'");
197                         }
198                         try {
199                             destroyMethod.invoke(this.bean, args);
200                         }
201                         catch (InvocationTargetException JavaDoc ex) {
202                             logger.error("Couldn't invoke destroy method '" + destroyMethodName +
203                                     "' of bean with name '" + this.beanName + "'", ex.getTargetException());
204                         }
205                         catch (Throwable JavaDoc ex) {
206                             logger.error("Couldn't invoke destroy method '" + destroyMethodName +
207                                     "' of bean with name '" + this.beanName + "'", ex);
208                         }
209                     }
210                 }
211             }
212             catch (IllegalArgumentException JavaDoc ex) {
213                 // thrown from findMethodWithMinimalParameters
214
logger.error("Couldn't find a unique destroy method on bean with name '" +
215                         this.beanName + ": " + ex.getMessage());
216             }
217         }
218     }
219
220
221     /**
222      * Serializes a copy of the state of this class,
223      * filtering out non-serializable BeanPostProcessors.
224      */

225     protected Object JavaDoc writeReplace() {
226         List JavaDoc serializablePostProcessors = null;
227         if (this.beanPostProcessors != null) {
228             serializablePostProcessors = new ArrayList JavaDoc();
229             for (Iterator JavaDoc it = this.beanPostProcessors.iterator(); it.hasNext();) {
230                 Object JavaDoc postProcessor = it.next();
231                 if (postProcessor instanceof Serializable JavaDoc) {
232                     serializablePostProcessors.add(postProcessor);
233                 }
234             }
235         }
236         return new DisposableBeanAdapter(this.bean, this.beanName, this.destroyMethodName,
237                 this.enforceDestroyMethod, serializablePostProcessors);
238     }
239
240 }
241
Popular Tags