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 java.util.HashMap;
014    import java.util.Map;
015    
016    import javax.management.DynamicMBean;
017    import javax.management.MBeanInfo;
018    import javax.management.ObjectName;
019    
020    import org.picocontainer.ComponentAdapter;
021    import org.picocontainer.PicoContainer;
022    
023    
024    /**
025     * A DynamicMBeanProvider, that creates DynamicMBeans for registered Pico components on the fly.
026     * @author Michael Ward
027     * @author Jörg Schaible
028     */
029    public class RegisteredMBeanConstructingProvider implements DynamicMBeanProvider {
030    
031        private final DynamicMBeanFactory factory;
032        private final Map registry;
033    
034        /**
035         * Construct a RegisteredMBeanConstructingProvider with a {@link StandardMBeanFactory} as default.
036         */
037        public RegisteredMBeanConstructingProvider() {
038            this(new StandardMBeanFactory());
039        }
040    
041        /**
042         * Construct a RegisteredMBeanConstructingProvider, that uses a specific {@link DynamicMBeanFactory}.
043         * @param factory
044         */
045        public RegisteredMBeanConstructingProvider(final DynamicMBeanFactory factory) {
046            this.factory = factory;
047            this.registry = new HashMap();
048        }
049    
050        /**
051         * Provide a DynamicMBean for the given Pico component. The implementation will lookup the component's key in the
052         * internal registry. Only components that were registered with additional information will be considered and a
053         * {@link DynamicMBean} will be created for them using the {@link DynamicMBeanFactory}. If the component key is of
054         * type class, it is used as management interface.
055         * @see org.picocontainer.gems.jmx.DynamicMBeanProvider#provide(PicoContainer, ComponentAdapter)
056         */
057        public JMXRegistrationInfo provide(final PicoContainer picoContainer, final ComponentAdapter componentAdapter) {
058            final Object key = componentAdapter.getComponentKey();
059            final MBeanInfoWrapper wrapper = (MBeanInfoWrapper)registry.get(key);
060            if (wrapper != null) {
061                final Object instance = componentAdapter.getComponentInstance(picoContainer, ComponentAdapter.NOTHING.class);
062                final Class management = wrapper.getManagementInterface() != null
063                                                                                 ? wrapper.getManagementInterface()
064                                                                                 : key instanceof Class
065                                                                                                       ? (Class)key
066                                                                                                       : instance
067                                                                                                               .getClass();
068                final DynamicMBean mBean = factory.create(instance, management, wrapper.getMBeanInfo());
069                return new JMXRegistrationInfo(wrapper.getObjectName(), mBean);
070            }
071            return null;
072        }
073    
074        /**
075         * Register a specific Pico component by key with an MBeanInfo and an ObjectName.
076         * @param componentKey The key of the Pico component.
077         * @param objectName The {@link ObjectName} of the MBean.
078         * @param management The management interface.
079         * @param mBeanInfo The {@link MBeanInfo} of the MBean.
080         */
081        public void register(
082                final Object componentKey, final ObjectName objectName, final Class management, final MBeanInfo mBeanInfo) {
083            registry.put(componentKey, new MBeanInfoWrapper(mBeanInfo, objectName, management));
084        }
085    
086        /**
087         * Register a specific Pico component by key with an MBeanInfo and an ObjectName.
088         * @param componentKey The key of the Pico component.
089         * @param objectName The {@link ObjectName} of the MBean.
090         * @param mBeanInfo The {@link MBeanInfo} of the MBean.
091         */
092        public void register(final Object componentKey, final ObjectName objectName, final MBeanInfo mBeanInfo) {
093            register(componentKey, objectName, null, mBeanInfo);
094        }
095    
096        /**
097         * Register a specific Pico component with an MBeanInfo and an ObjectName. The implementation class of the
098         * {@link DynamicMBean} must be the key of the Pico component.
099         * @param objectName The {@link ObjectName} of the MBean.
100         * @param mBeanInfo The {@link MBeanInfo} of the MBean.
101         */
102        public void register(final ObjectName objectName, final MBeanInfo mBeanInfo) {
103            try {
104                register(getClass().getClassLoader().loadClass(mBeanInfo.getClassName()), objectName, mBeanInfo);
105            } catch (final ClassNotFoundException e) {
106                throw new JMXRegistrationException("Cannot access class " + mBeanInfo.getClassName() + " of MBean", e);
107            }
108        }
109    
110        /**
111         * Register a specific Pico component by key with an ObjectName.
112         * @param componentKey The key of the Pico component.
113         * @param objectName The {@link ObjectName} of the MBean.
114         */
115        public void register(final Object componentKey, final ObjectName objectName) {
116            registry.put(componentKey, new MBeanInfoWrapper(null, objectName, null));
117        }
118    
119        /**
120         * Simple wrapper to tie a MBeanInfo to an ObjectName
121         */
122        private static class MBeanInfoWrapper {
123            private final MBeanInfo mBeanInfo;
124            private final ObjectName objectName;
125            private final Class managementInterface;
126    
127            MBeanInfoWrapper(final MBeanInfo mBeanInfo, final ObjectName objectName, final Class management) {
128                this.mBeanInfo = mBeanInfo;
129                this.objectName = objectName;
130                this.managementInterface = management;
131            }
132    
133            MBeanInfo getMBeanInfo() {
134                return mBeanInfo;
135            }
136    
137            ObjectName getObjectName() {
138                return objectName;
139            }
140    
141            Class getManagementInterface() {
142                return managementInterface;
143            }
144        }
145    
146    }