How to expose methods of a class dynamically.. using Model Mbean?
Hi,
Would like to expose methods of my POJO's dynamically.
for ex : my POJO wil have few getter and setter methods like getName(), setName()
Another POJO wil have methods like getAccntDetails(), setAccntDetails().
so how do i write a common Mbean implementation to expose both of these by JMX..using Model Mbean.
i saw a few examples, but at everyplace we need to mention those methods.
what if i have to adda a new POJO later.
Is this possible?
Thanks
Athahar
Athahar,
As an alternative to Model MBeans, you could consider the approach described in <http://weblogs.java.net/blog/emcmanus/archive/2006/10/build_your_own.html>.
If you do want to use Model MBeans, the example code in the documentation of the package javax.management.modelmbean would be a good starting point <http://download.java.net/jdk6/docs/api/javax/management/modelmbean/package-summary.html>. But as you've probably noticed it's quite a lot of work to build a Model MBean.
Here's a class that makes a Model MBean based on the public getters in an object. It should be straightforward to generalize it to include setters too.
public class POJOMBeanFactory {
public static ModelMBean makeMBean(Object resource) {
try {
return makeMBean2(resource);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static ModelMBean makeMBean2(Object resource)
throws JMException, InvalidTargetObjectTypeException {
Method[] methods = resource.getClass().getMethods();
List<Method> getters = new ArrayList<Method>();
for (Method method : methods) {
if (method.getName().startsWith("get") &&
!method.getName().equals("get") &&
!method.getName().equals("getClass") &&
method.getParameterTypes().length == 0 &&
method.getReturnType() != void.class)
getters.add(method);
}
int ngetters = getters.size();
ModelMBeanAttributeInfo[] attrs = new ModelMBeanAttributeInfo[ngetters];
ModelMBeanOperationInfo[] ops = new ModelMBeanOperationInfo[ngetters];
for (int i = 0; i < ngetters; i++) {
Method getter = getters.get(i);
String attrName = getter.getName().substring(3);
Descriptor attrD =
new DescriptorSupport(new String[] {
"name=" + attrName,
"descriptorType=attribute",
"getMethod=" + getter.getName()
});
attrs[i] = new ModelMBeanAttributeInfo(attrName,
attrName,
getter,
null,
attrD);
ops[i] = new ModelMBeanOperationInfo(getter.getName(),
getter);
}
ModelMBeanInfo mmbi =
new ModelMBeanInfoSupport(resource.getClass().getName(),
resource.getClass().getName(),
attrs,
null, // constructors
ops,
null); // notifications
ModelMBean mmb = new RequiredModelMBean(mmbi);
mmb.setManagedResource(resource, "ObjectReference");
return mmb;
}
}
Hi Eamonn,
Thanks .. I could work on that, and i could get the getter working for the POJO's.. but i tried a lot on trying to expose the setter methods..
private static ModelMBean makeMBean2(Object resource)
throws JMException, InvalidTargetObjectTypeException {
Method[] methods = resource.getClass().getMethods();
List<Method> operations = new ArrayList<Method>();
List<Method> getters = new ArrayList<Method>();
List<Method> setters = new ArrayList<Method>();
for (Method method : methods) {
if (method.getName().startsWith("get") &&
!method.getName().equals("get") &&
!method.getName().equals("getClass") &&
method.getParameterTypes().length == 0 &&
method.getReturnType() != void.class)
{
operations.add(method);
getters.add(method);
}
if (method.getName().startsWith("set") &&
!method.getName().equals("set"))
{
operations.add(method);
setters.add(method);
}
}
int opsSize = operations.size();
int ngetters = getters.size();
ModelMBeanAttributeInfo[] attrs = new ModelMBeanAttributeInfo[opsSize];
ModelMBeanOperationInfo[] ops = new ModelMBeanOperationInfo[opsSize];
for (int i = 0; i < ngetters; i++) {
Method getter = getters.get(i);
Method setter = setters.get(i);
String attrName = getter.getName().substring(3);
Descriptor attrD =
new DescriptorSupport(new String[] {
"name=" + attrName,
"descriptorType=attribute",
"getMethod=" + getter.getName()
});
attrs[i] = new ModelMBeanAttributeInfo(attrName,
attrName,
getter,
setter,
attrD);
ops[i] = new ModelMBeanOperationInfo(getter.getName(),
getter);
ops[ngetters+i] = new ModelMBeanOperationInfo(setter.getName(),
setter);
}
ModelMBeanInfo mmbi =
new ModelMBeanInfoSupport(resource.getClass().getName(),
resource.getClass().getName(),
attrs,
null, // constructors
ops,
null); // notifications
ModelMBean mmb = new RequiredModelMBean(mmbi);
mmb.setManagedResource(resource, "ObjectReference");
return mmb;
}
Can u please tell me where i'm going wrong?
Exception in thread "main" java.lang.RuntimeException: javax.management.IntrospectionException: bad getter arg count
at POJOMBeanFactory.makeMBean(POJOMBeanFactory.java:27)
at POJOMbeanAgent.<init>(POJOMbeanAgent.java:34)
at POJOMbeanAgent.main(POJOMbeanAgent.java:69)
Caused by: javax.management.IntrospectionException: bad getter arg count
at javax.management.MBeanAttributeInfo.attributeType(MBeanAttributeInfo.java:236)
at javax.management.MBeanAttributeInfo.<init>(MBeanAttributeInfo.java:122)
at javax.management.modelmbean.ModelMBeanAttributeInfo.<init>(ModelMBeanAttributeInfo.java:200)
at POJOMBeanFactory.makeMBean2(POJOMBeanFactory.java:68)
at POJOMBeanFactory.makeMBean(POJOMBeanFactory.java:23)
Thanks
Athahar
Hi Athahar,I guess your setter methods want an argument and have a void return type. I think line 27 is operations.add(method);for setter methodsHope this helps,Michele
Hi Athahar,
The logic that builds up the ModelMBeanAttributeInfo[] is wrong.
1) There's no guarantee that there will be as many getters as setters - in other
words, in the general case, getters.size() != setters.size()
2) There's no guarantee that getters.get(i) and setters.set(i) relates to the same
attribute: getters.get(i) could be the method <i>getFoo()</i> and setters.get(i)
could be the method <i>setBar()</i>
You can't do everything in a single loop, you need 3 loops:
What you would need to do is:
0) Allocate an array list to contain a yet unknown number of ModelMBeanAttributeInfo
1) loop over getters:
1.1) for each getter extract the attribute name
1.2) from the attribute name, construct the name of the corresponding setter method.
1.3) see whether you find a setter method by that name in setters
1.4) remove the setter method from the setters list.
1.5) construct the ModelMBeanAttributeInfo for that attribute, add it to the list
2) At this point, the setters list should only contain setters for which there was no
getter (will be empty unless there was a setFoo() without a getFoo() - which
usually won't happen). But just in case you will need to loop over the remaining
setters:
2.1) for each getter extract the attribute name
2.2) from the attribute name, construct the name of the corresponding setter method.
2.3) construct the ModelMBeanAttributeInfo for that attribute, add it to the list
3) Convert the ArrayList<ModelMBeanAttributeInfo> into an array (use
toArray())
4) Now loop over operations
4.1) for each operations construct a ModelMBeanOperationInfo object.
Hope this helps,
-- daniel
http://blogs.sun.com/jmxetc
