/****************************************************************************** * 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); } } }