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"};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[] 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);
String[] index = { "symbol" };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.
TabularType quoteTableType = new TabularType("quoteSnapshots",
"List of Quotes", snapshotType,
index);
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.
Very nice! Are the sources available for download by chance? Tis just much easier than copy and paste. Many thanks! K
ReplyDeleteUnfortunately, I do not have sources any more, you will have to copy paste.
ReplyDeleteThanks. This is a very helpful article.
ReplyDelete