Writing an MBean by implementing the
javax.management.DynamicMBean
interface can be a heavy
and tedious task.
MX4J provides the class
mx4j.AbstractDynamicMBean
as a base class to implement a
dynamic MBean.
This class handles most of the tedious work that must be done when implementing dynamic MBeans,
so that the MBean implementor has just to override few methods to provide the needed information required
to create the MBean.
The methods of the
AbstractDynamicMBean
class can be divided in 2 groups: the methods of the
DynamicMBean
interface and the methods added by
AbstractDynamicMBean
itself.
AbstractDynamicMBean
already implements all the methods of the
DynamicMBean
interface, and normally the MBean implementor does not have to override them.
The methods belonging to the second group are normally overridden by the MBean implementor to provide the MBean metadata information,
and are the following:
createMBeanAttributeInfo
</funcdef>, if the MBeans has manageable attributes
createMBeanOperationInfo
</funcdef>, if the MBeans has manageable operations
createMBeanNotificationInfo
</funcdef>, if the MBeans has manageable notifications
createMBeanConstructorInfo
</funcdef>, if the MBeans has manageable constructors
getMBeanDescription
</funcdef>
A third group of methods belongs to the subclass of
AbstractDynamicMBean
and are the implementation
methods, the ones that implement the functionality of the MBean itself (see below for an example).
Example 6.7. Subclassing
AbstractDynamicMBean
public class SimpleDynamic extends AbstractDynamicMBean { /* Method of the second group that is overridden */ protected MBeanAttributeInfo[] createMBeanAttributeInfo() { return new MBeanAttributeInfo[] { new MBeanAttributeInfo("Name", String.class.getName(), "The name", true, true, false) }; } /* Method of the second group that is overridden */ protected String getMBeanDescription() { return "A simple DynamicMBean"; } /* Method of the third group that implements the MBean functionality */ public String getName() { ... } /* Method of the third group that implements the MBean functionality */ public void setName(String name) { ... } }
As you can see above, no methods from the
DynamicMBean
interface needs to be implemented.
It is sufficient to override some (or all) of the methods of the second group, and provide the relative methods
of the third group.
Normally the MBean implementor extends
AbstractDynamicMBean
, but if the MBean already extends another
class it is sufficient to implement
DynamicMBean
and delegate to a subclass of
AbstractDynamicMBean
, having care of calling the
<funcdef>
setResource
</funcdef>
method (see example below).
Example 6.8. Delegating to
AbstractDynamicMBean
subclass
public class ComposedDynamic extends MyBaseClass implements DynamicMBean { /* Create an AbstractDynamicMBean subclass */ private AbstractDynamicMBean delegate = new AbstractDynamicMBean() { protected MBeanAttributeInfo[] createMBeanAttributeInfo() { return new MBeanAttributeInfo[] { new MBeanAttributeInfo("Status", int.class.getName(), "The status", true, true, false), new MBeanAttributeInfo("Enabled", boolean.class.getName(), "The enable status", true, false, true) }; } protected MBeanOperationInfo[] createMBeanOperationInfo() { return new MBeanOperationInfo[] { new MBeanOperationInfo("enable", "Enables this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION), new MBeanOperationInfo("disable", "Disables this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION) }; } }; private int status; private boolean enabled; public ComposedDynamicMBean() { // Set the actual resource delegate.setResource(this); } /* Implement the methods of DynamicMBean interface to delegate to the AbstractDynamicMBean subclass */ public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { return delegate.getAttribute(attribute); } // Do the same with all other methods of DynamicMBean interface ... /* Methods of the third group that implements MBean functionality */ public void setStatus(int status) { this.status = status; } public int getStatus() { return status; } public boolean isEnabled() { return this.enabled; } public void enable() { this.enabled = true; } public void disable() { this.enabled = false; } }
AbstractDynamicMBean
can also be used for non-invasive management: if you already have a component
but you don't want to change it to implement a management interface, you can set it as target of a subclass of
AbstractDynamicMBean
and provide the suitable metadata information.
Example 6.9. Subclassing
AbstractDynamicMBean
public class NonInvasiveDynamic extends AbstractDynamicMBean { /* Methods of the second group that are overridden */ protected MBeanOperationInfo[] createMBeanOperationInfo() { return new MBeanOperationInfo[] { new MBeanOperationInfo("start", "Starts this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION), new MBeanOperationInfo("stop", "Stops this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION) }; } protected String getMBeanDescription() { return "A non invasive DynamicMBean that manages resource"; } /* Constructor that takes the managed resource */ public NonInvasiveDynamic(ExternalService service) { // Set the actual resource that this MBean represents. setresource(service); } /* Old main, before JMX public static void main(String[] args) throws Exception { // Create the service ExternalService service = new ExternalService(); // Start the service service.start(); } */ public static void main(String[] args) throws Exception { // Create the service ExternalService service = new ExternalService(); MBeanServer server = MBeanServerFactory.createMBeanServer(); NonInvasiveDynamic mbean = new NonInvasiveDynamic(service); ObjectName name = new ObjectName("domain:key=value"); server.registerMBean(mbean, name); // Now start the service via JMX: // Few lines more, but now the service is manageable ! server.invoke(name, "start", null, null); } }
The example above shows how simple can be to plug JMX into already existing architectures, and how it is possible, in few lines of code, to make services manageable (and remotely manageable with JSR 160) without even impacting already existing service's code.