Tuesday, May 7, 2013

Dynamic JMX MBean at Runtime

Simple DynamicMBean to monitor 

JMX API Includes possibility to create "Dynamic MBean", whose management interface is determined at runtime. It means management interface can not be determined by looking at the source code. 

Here is a simple example using Spring.

JMX Bean Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

 <description>KPI Agent Context</description>
 
 <context:annotation-config />
 <context:component-scan base-package="com.test.dm.kpi.agent" />
 <!-- JMX Beans -->
 <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
        <property name="autodetect" value="true" />
        <property name="namingStrategy" ref="namingStrategy" />
        <property name="assembler" ref="assembler" />
 </bean>
 <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
 <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
         <property name="attributeSource" ref="jmxAttributeSource" />
 </bean>
 <bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
         <property name="attributeSource" ref="jmxAttributeSource" />
 </bean>
</beans>



Create DynamicMBean :

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ReflectionException;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;

@Component
@ManagedResource(objectName = "performancedyna:name=ProfilingDataDyna", description = "Profiling Data for dynamic profiled methods.")
public class ProfilingDataDynamicMBean implements DynamicMBean {


 protected Map<String, String> methodExecutionData  = new ConcurrentHashMap<String, String>();
 private MBeanAttributeInfo[] mbeanAttributesInfo = new MBeanAttributeInfo[2];
 private MBeanInfo mbeanInfo = null;
 
 public ProfilingDataDynamicMBean() {
  this.buildDynamicMBeanInfo();
 }
 
 @Override
 public Object getAttribute(String attribute) throws AttributeNotFoundException,
   MBeanException, ReflectionException {
  return methodExecutionData.get(attribute);
 }

 @Override
 public AttributeList getAttributes(String[] attributes) {
  if (attributes == null) {
   return new AttributeList();
  }
  final List<Attribute> result = new ArrayList<Attribute>(attributes.length);
   for (String attr : attributes) {
    result.add(new Attribute(attr, methodExecutionData.get(attr)));
   }
  return new AttributeList(result);
 }

 @Override
 public MBeanInfo getMBeanInfo() {
  return mbeanInfo;
 }

 @Override
 public Object invoke(String arg0, Object[] arg1, String[] arg2)
   throws MBeanException, ReflectionException {  
  return null;
 }

 @Override
 public void setAttribute(Attribute arg0) throws AttributeNotFoundException,
   InvalidAttributeValueException, MBeanException, ReflectionException {
 }

 @Override
 public AttributeList setAttributes(AttributeList arg0) {
  return null;
 }
 
 private void buildDynamicMBeanInfo() {
  mbeanAttributesInfo[0] = new MBeanAttributeInfo("TestAttribute1", "java.lang.String", "Its a test attribute 1", false, false, false);                   // writable
  mbeanAttributesInfo[1] = new MBeanAttributeInfo("TestAttribute2", "java.lang.String", "Its a test attribute 2", false, false, false);
  mbeanInfo = new MBeanInfo("com.test.dm.kpi.agent.application.ProfilingDataDynamicMBean", "ProfilingDataDynamicMBean", mbeanAttributesInfo, null, null, null);
  methodExecutionData.put("TestAttribute1", "Test Values 1");
  methodExecutionData.put("TestAttribute2", "Test Values 2");
 }
 
 
 private Map<String, String> getMethodExecutionData() {
  return methodExecutionData;
 }
 
 public void setMethodExecutionData(Map<String, String> methodExecutionData) {
  this.methodExecutionData = methodExecutionData;
 }
 
 public void addMethodExcutionData(String key, String value) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
  this.getMethodExecutionData().put(key, value);
 }
}


Adding Dynamic Attribute at Runtime:

User the ProfilingDataDynamicMBean to add execution data like below.

dataDynamicBean.addMethodExcutionData("TestAttribute1", (System.currentTimeMillis() + "1111"));



No comments:

Post a Comment