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    }