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ö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 }