Dynamic MBeans
Prev | Chapter 6. MX4J Tools | Next

## Dynamic MBeans

### AbstractDynamicMBean base class for DynamicMBean implementation

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` , if the MBeans has manageable attributes
- `createMBeanOperationInfo` , if the MBeans has manageable operations
- `createMBeanNotificationInfo` , if the MBeans has manageable notifications
- `createMBeanConstructorInfo` , if the MBeans has manageable constructors
- `getMBeanDescription`

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 `setResource` 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.

Prev | Home | Next
Chapter 6. MX4J Tools | Up | Naming MBeans