Saturday, July 26, 2008

JMX Model MBeans with Apache Commons Modeler

In previous blog entries, I demonstrated coding Model MBeans directly (“in the raw”) and using the Spring Framework. In both cases, two primary advantages of Model MBeans (highly descriptive nature and ability to present non-JMX objects as managed JMX resources) were realized. While writing the Java code to construct Model MBean metadata information is not difficult, it is tedious. The Spring Framework significantly eases this effort, but requires a dependency on Spring if the full descriptive nature of the Model MBean is to be realized via Spring’s JMX metadata annotations. For those who want rich descriptions of their Model MBeans, who want to reduce the Java code required to implement Model MBean metadata, and cannot or do not want a Spring dependency, the Apache Commons Modeler may be the appropriate answer.

As its name implies, the Apache Commons Modeler is part of the highly useful and varied Apache Commons project. For this blog entry, I am using Modeler 2.0.1. The Modeler 2.0.1 download includes a JAR file (commons-modeler-2.0.1.jar) and the XML DTD for Modeler XML metadata configuration files (mbeans-descriptors.dtd). The contents of this DTD can be viewed without downloading Modeler at the URL http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd.

I’ll be demonstrating how to register the same SimpleCalculator class as a Model MBean that was used in the previous blog entries with direct Model MBean creation and Spring-based Model MBean creation. For convenience, the SimpleCalculator class is reproduced here.

SimpleCalculator.java

package dustin.jmx.modelmbeans;

/**
* Simple calculator class intended to demonstrate how a class with no knowledge
* of JMX or management can be "wrapped" with ModelMBeans.
*
* @author Dustin
*/
public class SimpleCalculator implements SimpleCalculatorIf
{
/**
* 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.
*/
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.
*/
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.
*/
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.
*/
public double divide(final int dividend, final int divisor)
{
return dividend / divisor;
}
}


When using Apache Commons Modeler, most of the work is done in an XML metadata configuration file conforming to the DTD specified above. For this example, that XML file is shown next. The XML element and attribute names are largely self-explanatory and additional information on these can be found within the DTD definition at http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd.

simple-calculator-modeler.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mbeans-descriptors PUBLIC
"-//Apache Software Foundation//DTD Model MBeans Configuration File"
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
<mbeans-descriptors>
<mbean id="managedSimpleCalculatorBean"
name="ManagedSimpleCalculatorBean"
description="Applying JMX Model MBean with Apache Commons Modeler"
type="dustin.jmx.modelmbeans.SimpleCalculator">

<descriptor>
<field id="nameField" name="name" value="ModelMBeanInCommonsModeler" />
<field id="descriptorTypeField" name="descriptorType" value="mbean" />
</descriptor>

<operation id="addOperation"
name="add"
description="Integer Addition"
impact="INFO"
returnType="int">
<parameter id="augendParameter"
name="augend"
description="The first parameter in the addition (augend)."
type="int" />
<parameter id="addendParameter"
name="addend"
description="The second parameter in the addition (addend)."
type="int" />
</operation>

<operation id="subtractOperation"
name="subtract"
description="Integer Subtraction"
impact="INFO"
returnType="int">
<parameter id="minuendParameter"
name="minuend"
description="The first parameter in the substraction (minuend)."
type="int" />
<parameter id="subtrahendParameter"
name="subtrahend"
description="The second parameter in the subtraction (subtrahend)."
type="int" />
</operation>

<operation id="multiplyOperation"
name="multiply"
description="Integer Multiplication"
impact="INFO"
returnType="int">
<parameter id="factor1Parameter"
name="factor1"
description="The first factor in the multiplication."
type="int" />
<parameter id="factor2Parameter"
name="factor2"
description="The second factor in the multiplication."
type="int" />
</operation>

<operation id="divideOperation"
name="divide"
description="Integer Division"
impact="INFO"
returnType="double">
<parameter id="dividendParameter"
name="dividend"
description="The dividend in the division."
type="int" />
<parameter id="divisorParameter"
name="divisor"
description="The divisor in the division."
type="int" />
</operation>

</mbean>
</mbeans-descriptors>


My SimpleCalculator-based JMX Model MBeans examples (direct, Spring-based, and now Commons Modeler-based) have all focused on specifying MBean operations and their parameters. To see how to specify other portions of a Model MBean with Commons Modeler, see the "Modeler" section of the article Using Jakarta Commons, Part 2. Note that there have been a few changes since that article was written. The promotion of the Commons project from a sub-project of Apache Jakarta to its own Apache Commons project brought the name change and is a relatively minor change. However, several changes to the API have led to some of the methods used in previous examples being deprecated.

The next class is the main class that reads in the XML metadata configuration file and uses Modeler to register an MBean with the descriptive information provided in the XML file shown earlier. Note that this code explicitly looks up the XML file by name. I could have had Modeler pick up the metadata configuration implicitly by appropriately naming the XML file and including it in the same package as the code, but I chose to use the explicit loading for this example.


package dustin.jmx.modelmbeans;

import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import org.apache.commons.modeler.Registry;

/**
* The purpose of this class is to demonstrate use of ModelMBeans with Apache
* Commons Modeler.
*/
public class CommonsModelMBeanDemonstrator
{
/**
* Main functionality for using Modeler XML metadata to instantiate and
* register a Model MBean with the Platform MBean Server.
*/
public void applyCommonsModeler()
{
final String modelerMetadataFile = "simple-calculator-modeler.xml";
final SimpleCalculator calculator = new SimpleCalculator();
Registry registry = null;
final InputStream modelerXmlInputStream =
CommonsModelMBeanDemonstrator.class.getResourceAsStream(
modelerMetadataFile);

// Use getRegistry(Object,Object) rather than deprecated getRegistry()
registry = Registry.getRegistry(null, null);

// Use instance setMBeanServer method rather than class/static setServer
registry.setMBeanServer(ManagementFactory.getPlatformMBeanServer());
try
{
// The following two methods on Registry (loadMetadata and
// registerComponent) throw the checked and very general Exception,
// which must be captured here..
registry.loadMetadata(modelerXmlInputStream);
registry.registerComponent(
calculator,
"modelmbean:type=commons-modeler", // mbean registered object name
"dustin.jmx.modelmbeans.SimpleCalculator");
}
catch (IOException ioEx)
{
System.err.println(
"ERROR trying to load metadata into Commons Modeler Registry "
+ "from configuration file " + modelerMetadataFile + ":\n"
+ ioEx.getMessage() );
}
catch (Exception ex)
{
System.err.print( "ERROR trying to access metadata file "
+ modelerMetadataFile + ":\n" + ex.getMessage() );
}
}

/**
* 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());
}
}

/**
* Main driver to demonstrate Apache Commons Modeler used with JMX
* Model MBeans.
*
* @param arguments Command-line arguments.
*/
public static void main(final String[] arguments)
{
CommonsModelMBeanDemonstrator me = new CommonsModelMBeanDemonstrator();
me.applyCommonsModeler();
pause(1000000);
}
}


The following three screen snapshots demonstrate how the results look in JConsole.







As the above example has demonstrated, Apache Commons Modeler allows JMX Model MBean metadata to be shifted from hard-coded Java into external XML configuration files. Whether this is an advantage or not is dependent on the situation and developer preferences (some prefer Java coding over XML even for configuration like this). However, it is nice to have an alternative available for those who prefer their Model MBean metadata to be externally configurable.

ADDITIONAL REFERENCES

For additional information on Apache Commons Modeler, see the project’s home page and the previously referenced article Using Jakarta Commons, Part 2. One of the most useful resources for learning to apply Apache Commons Modeler is the Javadoc API documentation for the package org.apache.commons.modeler. This Javadoc-generated documentation is included with the Modeler download and the description for package org.apache.commons.modeler is highly useful in explaining how to use Modeler. Among other interesting pointers, this description specifies how to have Modeler XML configuration found implicitly, how to use manual Java MBean metadata application rather than XML configuration, and which methods of the Modeler API are now preferred and which are now deprecated ("strongly" in some cases).

No comments: