/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.compendium.internal.cm;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.util.StringUtils;
/**
* Utility class that detects and then invokes custom destroy methods for
* <managed-components>. Similar in functionality to DisposableBeanAdapter but
* simpler since it is used just by templating beans. While it could be easily
* implemented through a {@link DestructionAwareBeanPostProcessor}, due to the
* order of the callbacks invocations and the overlap, an adapter becomes a
* better choice.
*
* @author Costin Leau
* @see org.springframework.beans.factory.DisposableBean
*/
class ManagedFactoryDisposableInvoker {
/** logger */
private static final Log log = LogFactory.getLog(ManagedFactoryDisposableInvoker.class);
private final boolean isDisposable;
private final Method customSpringMethod;
private final Object[] customSpringMethodArgs;
private final Method customOsgiDestructionMethod;
enum DestructionCodes {
CM_ENTRY_DELETED(1), BUNDLE_STOPPING(2);
private Integer value;
/**
* Constructs a new <code>DestructionCodes</code> instance.
*
* @param value
*/
DestructionCodes(int value) {
this.value = Integer.valueOf(value);
}
public Integer getValue() {
return value;
}
}
/**
* Constructs a new <code>ManagedFactoryDisposableAdapter</code> instance.
*
* @param methodName destruction method name
*/
public ManagedFactoryDisposableInvoker(Class<?> beanClass, String methodName) {
this.isDisposable = DisposableBean.class.isAssignableFrom(beanClass);
if (StringUtils.hasText(methodName)) {
this.customSpringMethod = detectCustomSpringMethod(beanClass, methodName);
if (customSpringMethod != null) {
Class<?>[] types = customSpringMethod.getParameterTypes();
this.customSpringMethodArgs = ((types.length == 1 && types[0].equals(boolean.class)) ? new Object[] { Boolean.TRUE }
: null);
}
else {
this.customSpringMethodArgs = null;
}
this.customOsgiDestructionMethod = detectCustomOsgiMethod(beanClass, methodName);
}
else {
this.customSpringMethod = null;
this.customSpringMethodArgs = null;
this.customOsgiDestructionMethod = null;
}
}
private Method detectCustomSpringMethod(Class<?> beanClass, String methodName) {
Method m = BeanUtils.findMethod(beanClass, methodName, null);
if (m == null) {
m = BeanUtils.findMethod(beanClass, methodName, new Class[] { boolean.class });
}
return m;
}
private Method detectCustomOsgiMethod(Class<?> beanClass, String methodName) {
return BeanUtils.findMethod(beanClass, methodName, new Class[] { int.class });
}
public void destroy(String beanName, Object beanInstance, DestructionCodes code) {
// first invoke disposable bean
if (isDisposable) {
if (log.isDebugEnabled()) {
log.debug("Invoking destroy() on bean with name '" + beanName + "'");
}
try {
((DisposableBean) beanInstance).destroy();
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'";
if (log.isDebugEnabled()) {
log.warn(msg, ex);
}
else {
log.warn(msg + ": " + ex);
}
}
}
// custom callback (no argument)
invokeCustomMethod(beanName, beanInstance);
// custom callback (int argument)
invokeCustomMethod(beanName, beanInstance, code);
}
private void invokeCustomMethod(String targetName, Object target) {
if (customSpringMethod != null) {
invokeMethod(customSpringMethod, customSpringMethodArgs, targetName, target);
}
}
private void invokeCustomMethod(String targetName, Object target, DestructionCodes code) {
if (customOsgiDestructionMethod != null) {
invokeMethod(customOsgiDestructionMethod, new Object[] { code.getValue() }, targetName, target);
}
}
private void invokeMethod(Method method, Object[] args, String targetName, Object target) {
try {
method.invoke(target, args);
}
catch (InvocationTargetException ex) {
String msg = "Invocation of destroy method '" + method.getName() + "' failed on bean with name '"
+ targetName + "'";
if (log.isDebugEnabled()) {
log.warn(msg, ex.getTargetException());
}
else {
log.warn(msg + ": " + ex.getTargetException());
}
}
catch (Throwable ex) {
log.error("Couldn't invoke destroy method '" + method.getName() + "' on bean with name '" + targetName
+ "'", ex);
}
}
}