001/*****************************************************************************
002 * Copyright (C) NanoContainer Organization. All rights reserved.            *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD      *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file.                                                     *
007 *                                                                           *
008 * Original code by Joerg Schaible                                           *
009 *****************************************************************************/
010
011package org.picocontainer.gems.jmx;
012
013import org.picocontainer.ComponentAdapter;
014import org.picocontainer.PicoContainer;
015
016import javax.management.DynamicMBean;
017import javax.management.MBeanInfo;
018import javax.management.MalformedObjectNameException;
019import javax.management.ObjectName;
020
021
022/**
023 * A DynamicMBeanProvider that constructs StandardMBean instances that as long as an ObjectName and a MBeanInfo can be
024 * generated for the component.
025 * @author Jörg Schaible
026 */
027public abstract class AbstractConstructingProvider implements DynamicMBeanProvider {
028
029    /**
030     * Create a StandardMBean from the component provided by the ComponentAdapter. One of the registered
031     * {@link MBeanInfoProvider} instances must provide a {@link MBeanInfo} for the component and the registered
032     * {@link ObjectNameFactory} has to provide a proper {@link ObjectName}.
033     * <p>
034     * Note: An instance of the component is only created, if a management interface is available.
035     * </p>
036     * @see org.picocontainer.gems.jmx.DynamicMBeanProvider#provide(org.picocontainer.PicoContainer,
037     *      org.picocontainer.ComponentAdapter)
038     */
039    public JMXRegistrationInfo provide(final PicoContainer picoContainer, final ComponentAdapter componentAdapter) {
040
041        // locate MBeanInfo
042        MBeanInfo mBeanInfo = null;
043        MBeanInfoProvider[] mBeanInfoProviders = getMBeanInfoProviders();
044        for (int i = 0; i < mBeanInfoProviders.length && mBeanInfo == null; ++i) {
045            mBeanInfo = mBeanInfoProviders[i].provide(picoContainer, componentAdapter);
046        }
047
048                Class management = null;
049                try {
050                // throws ClassNotFoundException if not successful
051                         management = getManagementInterface(componentAdapter.getComponentImplementation(), mBeanInfo);
052                } catch (final ClassNotFoundException e) {
053                        // No management interface available
054                }
055
056                if( management != null || mBeanInfo != null ) {
057                        try {
058                                // create MBean
059                                final DynamicMBean mBean = getMBeanFactory().create(
060                                                componentAdapter.getComponentInstance(picoContainer,null), management, mBeanInfo);
061                                final ObjectName objectName = getObjectNameFactory().create(componentAdapter.getComponentKey(), mBean);
062                                if (objectName != null) {
063                                        return new JMXRegistrationInfo(objectName, mBean);
064                                }
065                        } catch (final MalformedObjectNameException e) {
066                                throw new JMXRegistrationException("Cannot create ObjectName for component '"
067                                                + componentAdapter.getComponentKey()
068                                                + "'", e);
069                        }
070                }
071                return null;
072    }
073
074    /**
075     * @return Returns the {@link DynamicMBeanFactory} to use.
076     */
077    protected abstract DynamicMBeanFactory getMBeanFactory();
078
079    /**
080     * Deliver the ObjectNameFactory used to provide the {@link ObjectName} instances registering the MBeans.
081     * @return Return the {@link ObjectNameFactory} instance.
082     */
083    protected abstract ObjectNameFactory getObjectNameFactory();
084
085    /**
086     * Deliver the MBeanInfoProvider instances to use. The instances are used in the delivered sequence to retrieve a
087     * {@link MBeanInfo} for a MBean to create. It is valid for an implementation to return an empty array.
088     * @return Return an array of {@link MBeanInfoProvider} instances.
089     */
090    protected abstract MBeanInfoProvider[] getMBeanInfoProviders();
091
092    /**
093     * Determin the management interface from the component implementation type and an optional MBeanInfo instance.
094     * @param implementation The type of the component's implementation.
095     * @param mBeanInfo The {@link MBeanInfo} to expose the component. May be <code>null</code>.
096     * @return Returns the management interface.
097     * @throws ClassNotFoundException Thrown if no interface can be determined.
098     */
099    protected abstract Class getManagementInterface(final Class implementation, final MBeanInfo mBeanInfo)
100            throws ClassNotFoundException;
101}