    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 Michael Ward                                                 *
    009     *****************************************************************************/
    010
    011    package org.picocontainer.gems.jmx;
    012
    013    import javax.management.DynamicMBean;
    014    import javax.management.InstanceNotFoundException;
    015    import javax.management.MBeanException;
    016    import javax.management.MBeanInfo;
    017    import javax.management.NotCompliantMBeanException;
    018    import javax.management.RuntimeOperationsException;
    019    import javax.management.StandardMBean;
    020    import javax.management.modelmbean.InvalidTargetObjectTypeException;
    021    import javax.management.modelmbean.ModelMBean;
    022    import javax.management.modelmbean.ModelMBeanInfo;
    023    import javax.management.modelmbean.RequiredModelMBean;
    024
    025
    026    /**
    027     * A factory for DynamicMBeans, that creates MBean instances using the classes {@link StandardMBean} and
    028     * {@link ModelMBean} provided by the JMX specification. The implementation offers special support for StandardMBeans
    029     * following the naming convention for their management interface using the class name of the component with an appended
    030     * <em>MBean</em>.
    031     * @author Michael Ward
    032     * @author J&ouml;rg Schaible
    033     */
    034    public class StandardMBeanFactory implements DynamicMBeanFactory {
    035
    036        /**
    037         * Create a StandardMBean for the component.
    038         * @param componentInstance {@inheritDoc}
    039         * @param management The management interface. If <code>null</code> the implementation will use the interface
    040         *            complying with the naming convention for management interfaces.
    041         * @param mBeanInfo The {@link MBeanInfo} to use. If <code>null</code> the {@link StandardMBean} will use an
    042         *            automatically generated one.
    043         * @return Returns a {@link StandardMBean}. If the <strong>mBeanInfo</strong> was not null, it is an instance of a
    044         *         {@link StandardNanoMBean}.
    045         * @see org.picocontainer.gems.jmx.DynamicMBeanFactory#create(java.lang.Object, java.lang.Class,
    046         *      javax.management.MBeanInfo)
    047         */
    048        public DynamicMBean create(final Object componentInstance, final Class management, final MBeanInfo mBeanInfo) {
    049            try {
    050                if (mBeanInfo == null) {
    051                    final Class managementInterface = getManagementInterface(componentInstance.getClass(), management, null);
    052                    return new StandardMBean(componentInstance, managementInterface);
    053                } else if (mBeanInfo instanceof ModelMBeanInfo) {
    054                    final ModelMBean mBean = new RequiredModelMBean((ModelMBeanInfo)mBeanInfo);
    055                    try {
    056                        mBean.setManagedResource(componentInstance, "ObjectReference");
    057                    } catch (final InvalidTargetObjectTypeException e) {
    058                        // N/A: "ObjectReference" is a valid reference type
    059                    } catch (final InstanceNotFoundException e) {
    060                        // N/A: the instance was a valid object
    061                    }
    062                    return mBean;
    063                } else {
    064                    final Class<?> managementInterface = getManagementInterface(
    065                            componentInstance.getClass(), management, mBeanInfo);
    066                    return new StandardNanoMBean(componentInstance, managementInterface, mBeanInfo);
    067                }
    068            } catch (final ClassNotFoundException e) {
    069                throw new JMXRegistrationException("Cannot load management interface for StandardMBean", e);
    070            } catch (final NotCompliantMBeanException e) {
    071                throw new JMXRegistrationException("Cannot create StandardMBean", e);
    072            } catch (final RuntimeOperationsException e) {
    073                throw new JMXRegistrationException("Cannot create ModelMBean", e);
    074            } catch (final MBeanException e) {
    075                throw new JMXRegistrationException("Cannot create ModelMBean", e);
    076            }
    077        }
    078
    079        private Class getManagementInterface(final Class type, final Class management, final MBeanInfo mBeanInfo)
    080                throws ClassNotFoundException {
    081            final Class managementInterface;
    082            if (management == null) {
    083                managementInterface = getDefaultManagementInterface(type, mBeanInfo);
    084            } else {
    085                managementInterface = management;
    086            }
    087            return managementInterface;
    088        }
    089
    090        /**
    091         * Determin the management interface for the given type. The class name of the given type is used as class name of
    092         * the mBean unless the caller has provided a {@link MBeanInfo}, the class name of the MBean is retrieved a
    093         * MBeanInfo that defines this name. Following the naming conventions is the name of the management interface the
    094         * same as the class name of the MBean with an appended <em>MBean</em>. The {@link ClassLoader} of the type is
    095         * used to load the interface type.
    096         * @param type The class of the MBean.
    097         * @param mBeanInfo The {@link MBeanInfo} for the MBean. May be <code>null</code>.
    098         * @return Returns the default management interface.
    099         * @throws ClassNotFoundException If the management interface cannot be found.
    100         */
    101        public Class getDefaultManagementInterface(final Class type, final MBeanInfo mBeanInfo)
    102                throws ClassNotFoundException {
    103            final ClassLoader classLoader = type.getClassLoader() != null ? type.getClassLoader() : Thread.currentThread()
    104                    .getContextClassLoader();
    105            return classLoader.loadClass((mBeanInfo == null ? type.getName() : mBeanInfo.getClassName()) + "MBean");
    106        }
    107    }