Pages

Wednesday, June 17, 2009

Open Mbeans Tutorial

Writing an MBean in java is very simple. But, when you want the return type to a table of data(say, some metrics) then simple Mbeans are not of much use. One way to get table of data as a return type is using a Open Mbeans. This tutorial gives a simple example of how to write an Open Mbean that returns Table of data.

Step 1: Define a dynamic MXBean by implementing interface "DynamicMBean".
public class QuoteMXBean implements DynamicMBean { 
public Object getAttribute(String attribute) throws AttributeNotFoundException,
MBeanException, ReflectionException{
//TODO
}
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException{
//TODO
}
public AttributeList getAttributes(String[] attributes){
//TODO
}
public AttributeList setAttributes(AttributeList attributes){
//TODO
}
public Object invoke(String actionName, Object params[], String signature[])
throws MBeanException, ReflectionException{
//TODO
}
public MBeanInfo getMBeanInfo(){
//TODO
}
}

Step 2:
A table is made up of rows. And each row is made up of columns. We will have to give exactly this description defining a table.
String[] itemNames = { "symbol", "localTimeStamp", "latestResponse"}; 
String[] itemDescriptions = { "Symbol",
"The Timestamp for the response as on server", "The response String from Quoteserver"};
OpenType[] itemTypes = { SimpleType.STRING,
SimpleType.STRING, SimpleType.STRING};
CompositeType snapshotType = new CompositeType("snapshot", "Quote Data",
itemNames, itemDescriptions, itemTypes);
All the variables can be made private and initialized either in a static block or in the constructor. The CompositeType just defined that each row will contain the columns "symbol", "localTimeStamp", "latestResponse". Now lets define the table type it self.
String[] index = { "symbol" }; 
TabularType quoteTableType = new TabularType("quoteSnapshots",
"List of Quotes", snapshotType,
index);
That is, a table type "quoteTableType" is a collection of rows given by Composite type "snapshotType". The "index" gives, the unique identification for the table.


Step 3:
Lets declare the table with type "quoteTableType".
private TabularDataSupport quoteSnapshot = new TabularDataSupport(quoteTableType); 

Please add the getter and setters for the same.


Step 4:
Lets implement getMBeanInfo().
OpenMBeanInfoSupport info; 
OpenMBeanAttributeInfoSupport[] attributes = new OpenMBeanAttributeInfoSupport[1];
OpenMBeanConstructorInfoSupport[] constructors = new OpenMBeanConstructorInfoSupport[1];
OpenMBeanOperationInfoSupport[] operations = new OpenMBeanOperationInfoSupport[4];
MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[0];

//Just one attribute
attributes[0] = new OpenMBeanAttributeInfoSupport("QuoteSnapshot",
"Table of quotes data", quoteSnapshotType, true, false,
false);
//No arg constructor
constructors[0] = new OpenMBeanConstructorInfoSupport(
"QuoteMXBean",
"Constructs a QuoteMXBean instance.",
new OpenMBeanParameterInfoSupport[0]);

//Just one operation

OpenMBeanParameterInfo[] params = new OpenMBeanParameterInfoSupport[0];
operations[0] = new OpenMBeanOperationInfoSupport(
"resetAndGetQuoteSnapshot",
"Reset and get the latest available data for the Quotes",
params, quoteSnapshotType,
MBeanOperationInfo.INFO);
//Build the info

info = new OpenMBeanInfoSupport(this .getClass().getName(),
"Quote - Open - MBean", attributes, constructors,
operations, notifications);

Step 5:
Implement getAttribute() and getAttributes().
 public Object getAttribute(String attributeName) throws AttributeNotFoundException, 
MBeanException, ReflectionException {
if (attributeName.equals("QuoteSnapshot")) {
return (TabularData)getQuoteSnapshot();
}
throw new AttributeNotFoundException("Cannot find "
+ attributeName + " attribute ");
}
public AttributeList getAttributes(String[] attributeNames) {
AttributeList resultList = new AttributeList();
if (attributeNames.length == 0)
return resultList;
for (int i = 0; i < attributeNames.length; i++) {
try {
Object value = getAttribute(attributeNames[i]);
resultList.add(new Attribute(attributeNames[i], value));
} catch (Exception e) {
e.printStackTrace();
}
}
return (resultList);
}

Step 6:
Implement setAttribute().
There is nothing to set in this example.
    public void setAttribute(Attribute arg0) throws AttributeNotFoundException, 
InvalidAttributeValueException, MBeanException, ReflectionException {
throw new AttributeNotFoundException(
"No attribute can be set in this MBean");
}

@Override
public AttributeList setAttributes(AttributeList arg0) {
return new AttributeList();
}

Step 7:
Implement invoke().
public Object invoke(String operationName, Object[] params, String[] signature) 
throws MBeanException, ReflectionException {
if (operationName.equals("resetAndGetQuoteSnapshot")) {
try {
return buildSnapshot(); //This is where you delegate the invokation to your original method.
} catch (OpenDataException e) {
throw new MBeanException(e, "invoking resetAndGetQuoteSnapshot: "
+ e.getClass().getName() + "caught ["
+ e.getMessage() + "]");
}
}
else{
throw new ReflectionException(new NoSuchMethodException(
operationName), "Cannot find the operation "
+ operationName);
}
}
public Object buildSnapshot() throws OpenDataException {
quoteSnapshot = new TabularDataSupport(quoteTableType);
SomeVo vo = //get the data
Object[] itemValues = { vo.symbol, vo.localDate, vo.response};
CompositeData result = new CompositeDataSupport(snapshotType,
itemNames, itemValues);
quoteSnapshot.put(result);
return quoteSnapshot;
}

This is all is needed to build an Open MBean that supports a Tabular data as output. You can use jconsole and view the output. Obviously, you have to deploy the MBean in mbean server. I use spring to do that job. The spring XML is given below.
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false"> 
<property name="beans">
<map>
<entry key="com.ssb.mbean:type=QuoteMXBean" value-ref="quoteMXBean"/>
</map>
</property>
</bean>
<bean id="quoteMXBean" class="com.ssb.mbean.QuoteMXBean"/>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"
p:port="9999" />
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean"
p:objectName="connector:name=rmi"
p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:9999/quotesconnector"
p:threaded="true"
p:daemon="true"/>

The above example is trying to display the latest quote data that is available to the system.

3 comments:

  1. Very nice! Are the sources available for download by chance? Tis just much easier than copy and paste. Many thanks! K

    ReplyDelete
  2. Unfortunately, I do not have sources any more, you will have to copy paste.

    ReplyDelete
  3. Thanks. This is a very helpful article.

    ReplyDelete