Thursday, August 7, 2008

JMX Model MBeans with EasyMBean

I wrote previous blog entries on the advantages of using Model MBeans and showed examples of using Model MBeans directly, using Model MBeans with the Spring Framework, and using Model MBeans with Apache Commons Modeler. In this blog entry, I will look at using Model MBeans with EasyMBean.

A JMX developer might choose to use EasyMBeans for his or her Model MBean needs if he or she was not using the Spring Framework anywhere else in a given Java application, but wanted Spring-like JMX ModelMBean annotations. Other choices include direct Model MBean coding and using Apache Commons Modeler, but EasyMBean is most like Spring in terms of JMX Model MBean exposure.

EasyMBean has a close relationship with JManage. Not only is EasyMBean discussed heavily at the jManage site, but "jmanage" appears in the package names for EasyMBeans classes as shown in this blog entry's code examples. However, it is important to note that jManage is not required and that a standalone version of EasyMBean.jar can be downloaded from the EasyMBean project site.

For my example of using EasyMBean in this blog entry, I have adapted the class SimpleCalculatorAnnotated that I demonstrated with Spring and Model MBeans in my previous blog entry. The name of this adapted class is SimpleCalculatorAnnotatedEasyMBean and its code lsiting is shown next:

SimpleCalculatorAnnotatedEasyMBean.java

package dustin.jmx.modelmbeans;

import org.jmanage.easymbean.annotations.ManagedConstructor;
import org.jmanage.easymbean.annotations.ManagedOperation;
import org.jmanage.easymbean.annotations.ManagedResource;


/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be annotated to be exposed as Model MBean by EasyMBean.
*
* @author Dustin
*/
@ManagedResource(
name="modelmbean:type=spring-annotated",
description="A simple integer calculator." )
public class SimpleCalculatorAnnotatedEasyMBean implements SimpleCalculatorIf
{
@ManagedConstructor(
name="SimpleCalculatorAnnotatedEasyMBean",
description="No argument constructor")
public SimpleCalculatorAnnotatedEasyMBean()
{
}

/**
* Calculate the sum of the augend and the addend.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @return Sum of augend and addend.
*/
@ManagedOperation(
name="add",
displayName="Integer Addition",
presentationString="Integer Addition",
targetClass="SimpleCalculatorAnnotatedEasyMBean",
description="Integer Addition")
public int add(final int augend, final int addend)
{
return augend + addend;
}

/**
* Calculate the difference between the minuend and subtrahend.
*
* @param minuend Minuend in subtraction operation.
* @param subtrahend Subtrahend in subtraction operation.
* @return Difference of minuend and subtrahend.
*/
@ManagedOperation(
name="subtract",
displayName="Integer Subtraction",
presentationString="Integer Subtraction",
targetClass="SimpleCalculatorAnnotatedEasyMBean",
description="Integer Subtraction")
public int subtract(final int minuend, final int subtrahend)
{
return minuend - subtrahend;
}

/**
* Calculate the product of the two provided factors.
*
* @param factor1 First integer factor.
* @param factor2 Second integer factor.
* @return Product of provided factors.
*/
@ManagedOperation(
name="multiply",
displayName="Integer Multiplication",
presentationString="Integer Multiplication",
targetClass="SimpleCalculatorAnnotatedEasyMBean",
description="Integer Multiplication")
public int multiply(final int factor1, final int factor2)
{
return factor1 * factor2;
}

/**
* Calculate the quotient of the dividend divided by the divisor.
*
* @param dividend Integer dividend.
* @param divisor Integer divisor.
* @return Quotient of dividend divided by divisor.
*/
@ManagedOperation(
name="divide",
displayName="Integer Division",
presentationString="Integer Division",
targetClass="SimpleCalculatorAnnotatedEasyMBean",
description="Integer Division")
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


The code listing for SimpleCalculatorAnnotatedEasyMBean shares many similarities with the Spring version, but there are significant differences. The most obvious and expected difference is the different set of import statements. However, there are deeper differences as well. In this case, the focus is on describing Model MBean operations (methods) and EasyMBean does not allow the parameters to the operations to be explicitly described like Spring does. While this does make it simpler for the developer (as stated in EasyMBean documentation), it is also a limitation because the parameters show up in JConsole and other generic JMX consoles as something like "p1" and "p2" rather than with their descriptive names.

One other thing worthy of special note here is the use of an EasyMBean-annotated no-argument constructor in the bean class. I found this necessary to allow my sample application to run without a NullPointerException.

The next code listing, for class EasyMBeanDemonstrator, shows the code to get access to the platform MBean server and then to use the EasyMBean static call to EasyMBean.getMBean(Object,ObjectName,MBeanServer) method.

EasyMBeanDemonstrator.java

package dustin.jmx.modelmbeans;

import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import org.jmanage.easymbean.EasyMBean;

/**
* This class demonstrates use of EasyMBean to annotate classes for exposure
* as Model MBeans.
*
* For more information on EasyMBeans, see the JManage documentation at
* http://www.jmanage.org/wiki/index.php/EasyMBean along with the main project
* page at http://sourceforge.net/projects/easymbean/.
*
* @author Dustin
*/
public class EasyMBeanDemonstrator
{
/**
* Register the ModelMBean in the MBeanServer using the provided
* ObjectName String.
*
* @param objectNameString ObjectName of the registered ModelMBean.
*/
private void registerModelMBean(
final String objectNameString)
{
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
SimpleCalculatorAnnotatedEasyMBean mbean =
new SimpleCalculatorAnnotatedEasyMBean();
try
{
final ObjectName objectName =
new ObjectName(objectNameString);
final ObjectInstance objInstance =
EasyMBean.getMBean(mbean, objectName, mbs);
/*
this.mbeanServer.registerMBean( modelMBean,
objectName );*/
}
catch (MalformedObjectNameException badObjectName)
{
System.err.println( "ERROR trying to generate ObjectName based on "
+ objectNameString + ":\n"
+ badObjectName.getMessage() );
}
}

/**
* Create a ModelMBean in the raw and register it with the MBeanServer.
*/
public void createAndRegisterEasyMBean()
{
final String easyModelMBeanObjectNameString = "modelmbean:type=easyMBean";
registerModelMBean(easyModelMBeanObjectNameString);
}

/**
* Pause for the specified number of milliseconds.
*
* @param millisecondsToPause Milliseconds to pause execution.
*/
public static void pause(final int millisecondsToPause)
{
try
{
Thread.sleep(millisecondsToPause);
}
catch (InterruptedException threadAwakened)
{
System.err.println("Don't wake me up!\n" + threadAwakened.getMessage());
}
}

/**
* Demonstrate use of ModelMBean via EasyMBean..
*
* @param args the command line arguments
*/
public static void main(String[] args)
{
final EasyMBeanDemonstrator me = new EasyMBeanDemonstrator();
me.createAndRegisterEasyMBean();
pause(1000000);
}
}


With the above code in place, I will now show two screen snapshots that show the results of this simple work in JConsole. There is more detail in JConsole than one would see in a non-annotated Spring Model MBean, but less than one would see when Spring's annotation-based support is used. The most noticeable feature missing is the lack of names for the parameters to the operations.





I've attempted to demonstrate the simplicity of EasyMBean in employing Model MBeans in JMX development. When I am using Spring in my Java-based applications, I'd almost certainly stick with Spring's support, but EasyMBean is worth consideration when not otherwise using Spring.

Perhaps the most approachable resource available online that describes how to use EasyMBean is provided as part of the jManage site. The EasyMBean Wiki entry at this site provides a "Quick Start for the impatient" section and a more descriptive (but still pretty brief) "Understanding EasyMBean Annotations for the Cool Headed" section. The first section demonstrates code examples of using EasyMBean similar to those shown here and the second section explains each major EasyMBean annotation and its attributes in detail. My blog entry focused on operations, but this resource shows how EasyMBean annotations can also be used with JMX Notifications and attributes.

Finally, JMX 2.0 appears likely to provide JMX developers with the standard support for JMX annotations, which will likely be the favorite choice of most JMX developers. For more details on the forthcoming JMX 2.0 support for JMX annotations, see Eamonn McManus's blog entries Playing with the JMX 2.0 API and Defining MBeans with Annotations.

No comments: