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.