+ All Categories
Home > Documents > Implementing the DynamicMBean Interface

Implementing the DynamicMBean Interface

Date post: 14-Oct-2014
Category:
Upload: christophe-hamerling
View: 1,560 times
Download: 1 times
Share this document with a friend
Description:
How to implements the DynamicMBean interface to manage properties and set of methods.
Popular Tags:
17
Implementing DynamicMBean interface Introduction Using JMX (Java Management eXtensions) to manage part of your application is a great java feature. The standard Mbeans mechanisms which consist of creating a classwhich implements an MBean interface is quite simple and already allows to manage most of your application. In this article, I will describe how can we implements the DynamicMBean interface to do more 'complex' things. Especially, we will look on how we can we expose and modify a set of properties, and how can we expose methods by specifiing their names (The java code will be more clear than my poor english). The following examples are taken from the work I have done on the PEtALS CDK (Component Development Kit) in order to expose a set of JBI extensions and bootstrap methods for management. How to expose a set of properties? The standards MBeans automatically expose the setters and getters methods as MBean attributes. Imagine that you have a set of properties (a HashMap/Properties...). How can you manage this object, how can you change a value in the set? Simply by creating an implementation of the DynamicMBean interface. The following code snippet shows how we can do such a thing. /* * (non-Javadoc) * * @see javax.management.DynamicMBean#getAttribute(java.lang.String) */ public synchronized Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { String value = managedBootstrap.getComponentPropertiesManager() .getProperties().getProperty(attribute); if (value != null && !value .startsWith(ComponentPropertiesManager.MANAGED_METHOD_PREFIX)) { return value; } else { throw new AttributeNotFoundException("Attribute '" + attribute + "' does not exists");
Transcript
Page 1: Implementing the DynamicMBean Interface

Implementing DynamicMBean interface

Introduction

Using JMX (Java Management eXtensions) to manage part of your application is a great java feature. The standard Mbeans mechanisms which consist of creating a class which implements an MBean interface is quite simple and already allows to manage most of your application.In this article, I will describe how can we implements the DynamicMBean interface to do more 'complex' things. Especially, we will look on how we can we expose and modify a set of properties, and how can we expose methods by specifiing their names (The java code will be more clear than my poor english).

The following examples are taken from the work I have done on the PEtALS CDK (Component Development Kit) in order to expose a set of JBI extensions and bootstrap methods for management.

How to expose a set of properties?

The standards MBeans automatically expose the setters and getters methods as MBean attributes. Imagine that you have a set of properties (a HashMap/Properties...). How can you manage this object, how can you change a value in the set? Simply by creating an implementation of the DynamicMBean interface.

The following code snippet shows how we can do such a thing.

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getAttribute(java.lang.String)

*/

public synchronized Object getAttribute(String attribute)

throws AttributeNotFoundException, MBeanException, ReflectionException {

String value = managedBootstrap.getComponentPropertiesManager()

.getProperties().getProperty(attribute);

if (value != null

&& !value

.startsWith(ComponentPropertiesManager.MANAGED_METHOD_PREFIX)) {

return value;

} else {

throw new AttributeNotFoundException("Attribute '" + attribute

+ "' does not exists");

Page 2: Implementing the DynamicMBean Interface

}

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getAttributes(java.lang.String[])

*/

public synchronized AttributeList getAttributes(String[] attributes) {

AttributeList list = new AttributeList();

for (String name : attributes) {

String value = managedBootstrap.getComponentPropertiesManager()

.getProperties().getProperty(name);

if (value != null

&& !value

.startsWith(ComponentPropertiesManager.MANAGED_METHOD_PREFIX))

list.add(new Attribute(name, value));

}

return list;

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute)

*/

public synchronized void setAttribute(Attribute attribute)

throws AttributeNotFoundException, InvalidAttributeValueException,

MBeanException, ReflectionException {

String name = attribute.getName();

if (managedBootstrap.getComponentPropertiesManager().getProperties()

.getProperty(name) == null) {

Page 3: Implementing the DynamicMBean Interface

throw new AttributeNotFoundException(name);

}

Object value = attribute.getValue();

if (!(value instanceof String)) {

throw new InvalidAttributeValueException(

"Attribute value not a string: " + value);

}

// set the property and save the properties file

managedBootstrap.getComponentPropertiesManager().getProperties()

.setProperty(name, (String) value);

try {

save();

} catch (IOException e) {

throw new MBeanException(e);

}

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList)

*/

public synchronized AttributeList setAttributes(AttributeList list) {

AttributeList result = new AttributeList();

for (Object object : list) {

Attribute attr = (Attribute) object;

String name = attr.getName();

Object value = attr.getValue();

if (managedBootstrap.getComponentPropertiesManager()

Page 4: Implementing the DynamicMBean Interface

.getProperties().getProperty(name) != null

&& value instanceof String) {

managedBootstrap.getComponentPropertiesManager()

.getProperties().setProperty(name, (String) value);

result.add(new Attribute(name, value));

}

}

try {

save();

} catch (IOException e) {

return new AttributeList();

}

return result;

}

The previous methods are the ones which are called by the JMX implementation for management. In our case it is quite simple since a property entry is directly mapped into an attribute...

Note 1 : The managedBootstrap attribute is a class which contains a Properties object.Note 2 : We persist the properties in a file each time a property is modified.

In order to expose these attributes, we will see later that we need to create a set of MBeanAttributeInfo that will be used by the getMBeanInfo method to create the information object used by JMX to expose all of this.

/**

* Dynamically get attributes for the MBean. The attributes are the ones

* from the properties file.

*

* @return

*/

protected MBeanAttributeInfo[] getAttributesInfos() {

// get the attributes names as sorted strings

Set<String> attributeKeys = managedBootstrap

.getComponentPropertiesManager().getExposedAttributeKeys();

Page 5: Implementing the DynamicMBean Interface

// build the MBeanAttributeInfo

MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[attributeKeys

.size()];

Iterator<String> it = attributeKeys.iterator();

for (int i = 0; i < attrs.length; i++) {

String name = it.next();

attrs[i] = new MBeanAttributeInfo(name, "java.lang.String",

"Property " + name, true, true, false);

}

return attrs;

}

How to expose a set of methods?

Building the MBeanInfo

In the previous chapter, I have introduced how we can dynamically expose properties. Now we will focus on how we can choose the methods to expose through JMX. There are several methods to do this. Here I have choosen to expose only the public methods that are programatically defined in a list. I have choosen this simple way to allow the component developer to simply define the methods he wants to expose by returning a list of methods names... Simple and efficient!

/**

* Dynamically get the operations for the MBean. The operations are defined

* in the properties manager with a special prefix.

*

* @return

*/

protected MBeanOperationInfo[] getOperationsInfos() {

List<String> methods = managedBootstrap.getComponentPropertiesManager()

.getExposedMethodNames();

MBeanOperationInfo[] result = null;

Page 6: Implementing the DynamicMBean Interface

List<MBeanOperationInfo> operations = new ArrayList<MBeanOperationInfo>();

Method methodList[] = managedBootstrap.getClass().getMethods();

for (int i = 0; i < methodList.length; i++) {

Method method = methodList[i];

String name = method.getName();

// add method if it has been defined by the user

if (methods.contains(name)) {

MBeanOperationInfo oper = new MBeanOperationInfo(

"Operation description", method);

operations.add(oper);

}

}

result = new MBeanOperationInfo[operations.size()];

operations.toArray(result);

return result;

}

This time again, we are are creating a set of MBeanOperationInfo from a list methods names. We retrieve the methods from the class we want to manage from the managedBootstrap class by reflection.

This method will be then used to create the MBeanInfo that is returned by the method getMBeanInfo:

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getMBeanInfo()

*/

public synchronized MBeanInfo getMBeanInfo() {

// get the attributes

MBeanAttributeInfo[] attrs = getAttributesInfos();

// get the operations

Page 7: Implementing the DynamicMBean Interface

MBeanOperationInfo[] opps = getOperationsInfos();

// create MBeanInfo with no constructors and no notifications

return new MBeanInfo(this.getClass().getName(),

"Property Manager MBean", attrs, null, opps, null);

}

Invoking a method

Doing java reflection is out of this article scope. Have a look on the implementation to see how it is done.

Complete implementation

/**

* PETALS - PETALS Services Platform.

* Copyright (c) 2007 EBM Websourcing, http://www.ebmwebsourcing.com/

*

* This library is free software; you can redistribute it and/or

* modify it under the terms of the GNU Lesser General Public

* License as published by the Free Software Foundation; either

* version 2.1 of the License, or (at your option) any later version.

* This library is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

* Lesser General Public License for more details.

*

* You should have received a copy of the GNU Lesser General Public

* License along with this library; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*

* -------------------------------------------------------------------------

Page 8: Implementing the DynamicMBean Interface

* $Id$

* -------------------------------------------------------------------------

*/

package org.objectweb.petals.component.common;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.Hashtable;

import java.util.Iterator;

import java.util.List;

import java.util.Set;

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.MBeanOperationInfo;

import javax.management.ReflectionException;

import javax.management.RuntimeOperationsException;

/**

* The MBean used to expose component attributes and operations via JMX.

*

* @author Christophe HAMERLING - eBMWebSourcing

*

*/

Page 9: Implementing the DynamicMBean Interface

public class ExtensionMBean implements DynamicMBean {

private ManagedBootstrap managedBootstrap;

private final static Hashtable<String, Class<?>> primitiveClasses = new Hashtable<String, Class<?>>(

8);

{

primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);

primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);

primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);

primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);

primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);

primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);

primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);

primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);

}

/**

* Creates a new instance of {@link ExtensionMBean}

*

* @param bootstrap

*/

public ExtensionMBean(ManagedBootstrap bootstrap) {

this.managedBootstrap = bootstrap;

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getAttribute(java.lang.String)

*/

public synchronized Object getAttribute(String attribute)

throws AttributeNotFoundException, MBeanException, ReflectionException {

Page 10: Implementing the DynamicMBean Interface

String value = managedBootstrap.getComponentPropertiesManager()

.getProperties().getProperty(attribute);

if (value != null

&& !value

.startsWith(ComponentPropertiesManager.MANAGED_METHOD_PREFIX)) {

return value;

} else {

throw new AttributeNotFoundException("Attribute '" + attribute

+ "' does not exists");

}

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getAttributes(java.lang.String[])

*/

public synchronized AttributeList getAttributes(String[] attributes) {

AttributeList list = new AttributeList();

for (String name : attributes) {

String value = managedBootstrap.getComponentPropertiesManager()

.getProperties().getProperty(name);

if (value != null

&& !value

.startsWith(ComponentPropertiesManager.MANAGED_METHOD_PREFIX))

list.add(new Attribute(name, value));

}

return list;

}

/*

Page 11: Implementing the DynamicMBean Interface

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute)

*/

public synchronized void setAttribute(Attribute attribute)

throws AttributeNotFoundException, InvalidAttributeValueException,

MBeanException, ReflectionException {

String name = attribute.getName();

if (managedBootstrap.getComponentPropertiesManager().getProperties()

.getProperty(name) == null) {

throw new AttributeNotFoundException(name);

}

Object value = attribute.getValue();

if (!(value instanceof String)) {

throw new InvalidAttributeValueException(

"Attribute value not a string: " + value);

}

// set the property and save the properties file

managedBootstrap.getComponentPropertiesManager().getProperties()

.setProperty(name, (String) value);

try {

save();

} catch (IOException e) {

throw new MBeanException(e);

}

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList)

Page 12: Implementing the DynamicMBean Interface

*/

public synchronized AttributeList setAttributes(AttributeList list) {

AttributeList result = new AttributeList();

for (Object object : list) {

Attribute attr = (Attribute) object;

String name = attr.getName();

Object value = attr.getValue();

if (managedBootstrap.getComponentPropertiesManager()

.getProperties().getProperty(name) != null

&& value instanceof String) {

managedBootstrap.getComponentPropertiesManager()

.getProperties().setProperty(name, (String) value);

result.add(new Attribute(name, value));

}

}

try {

save();

} catch (IOException e) {

return new AttributeList();

}

return result;

}

/*

* (non-Javadoc)

*

* @see javax.management.DynamicMBean#getMBeanInfo()

*/

public synchronized MBeanInfo getMBeanInfo() {

// get the attributes

Page 13: Implementing the DynamicMBean Interface

MBeanAttributeInfo[] attrs = getAttributesInfos();

// get the operations

MBeanOperationInfo[] opps = getOperationsInfos();

// create MBeanInfo with no constructors and no notifications

return new MBeanInfo(this.getClass().getName(),

"Property Manager MBean", attrs, null, opps, null);

}

/**

* Dynamically get the operations for the MBean. The operations are defined

* in the properties manager with a special prefix.

*

* @return

*/

protected MBeanOperationInfo[] getOperationsInfos() {

List<String> methods = managedBootstrap.getComponentPropertiesManager()

.getExposedMethodNames();

MBeanOperationInfo[] result = null;

List<MBeanOperationInfo> operations = new ArrayList<MBeanOperationInfo>();

Method methodList[] = managedBootstrap.getClass().getMethods();

for (int i = 0; i < methodList.length; i++) {

Method method = methodList[i];

String name = method.getName();

// add method if it has been defined by the user

if (methods.contains(name)) {

MBeanOperationInfo oper = new MBeanOperationInfo(

"Operation description", method);

operations.add(oper);

}

}

Page 14: Implementing the DynamicMBean Interface

result = new MBeanOperationInfo[operations.size()];

operations.toArray(result);

return result;

}

/**

* Dynamically get attributes for the MBean. The attributes are the ones

* from the properties file.

*

* @return

*/

protected MBeanAttributeInfo[] getAttributesInfos() {

// get the attributes names as sorted strings

Set<String> attributeKeys = managedBootstrap

.getComponentPropertiesManager().getExposedAttributeKeys();

// build the MBeanAttributeInfo

MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[attributeKeys

.size()];

Iterator<String> it = attributeKeys.iterator();

for (int i = 0; i < attrs.length; i++) {

String name = it.next();

attrs[i] = new MBeanAttributeInfo(name, "java.lang.String",

"Property " + name, true, true, false);

}

return attrs;

}

/*

* (non-Javadoc)

*

Page 15: Implementing the DynamicMBean Interface

* @see javax.management.DynamicMBean#invoke(java.lang.String,

* java.lang.Object[], java.lang.String[])

*/

public Object invoke(String actionName, Object[] params, String[] signature)

throws MBeanException, ReflectionException {

Object result = null;

final Class objClass = managedBootstrap.getClass();

final ClassLoader loader = objClass.getClassLoader();

final Class[] parameters = ((signature == null) ? null

: findSignatureClasses(signature, loader));

// Query the metadata service to get the right method

//

Method method = null;

try {

method = objClass.getMethod(actionName, parameters);

} catch (Exception e) {

}

if (method == null) {

throw new ReflectionException(

new NoSuchMethodException(actionName),

"The operation with name " + actionName + " could not be found");

}

try {

// invoke method

result = method.invoke(managedBootstrap, params);

} catch (IllegalAccessException e) {

throw new ReflectionException(e, "IllegalAccessException"

+ " occured trying to invoke operation " + actionName);

} catch (RuntimeException e) {

Page 16: Implementing the DynamicMBean Interface

throw new RuntimeOperationsException(e, "RuntimeException"

+ " occured trying to invoke operation " + actionName);

} catch (InvocationTargetException e) {

throw new MBeanException(e, "Exception thrown in operation "

+ actionName);

}

return result;

}

/**

* Find the classes of the signature

*

* @param signature

* @param loader

* @return

* @throws ReflectionException

*/

private Class[] findSignatureClasses(String signature[], ClassLoader loader)

throws ReflectionException {

if (signature == null)

return null;

final int length = signature.length;

final Class tab[] = new Class[length];

if (length == 0)

return tab;

try {

for (int i = 0; i < length; i++) {

// try to get the primitive class

final Class primCla = (Class) primitiveClasses

.get(signature[i]);

Page 17: Implementing the DynamicMBean Interface

if (primCla != null) {

tab[i] = primCla;

} else {

// try to get the class if not primitive one

tab[i] = Class.forName(signature[i], false, loader);

}

}

} catch (ClassNotFoundException e) {

throw new ReflectionException(e,

"The parameter class could not be found");

} catch (RuntimeException e) {

throw e;

}

return tab;

}

/**

* Save the properties to a file

*

* @throws IOException

*/

private void save() throws IOException {

managedBootstrap.getComponentPropertiesManager().save();

}

About

I am a software engineer and community manager on the open source PEtALS ESB project at eBM WebSourcing.You can get this article as PDF file on my scribd space or on my work blog.


Recommended