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 }