Wednesday, June 4, 2014

JMX, MXBeans – random thoughts and ideas

JMX, MXBeans – random thoughts and ideas


JMX has been around for a while. A very common use for JMX is to add it as a debug interface to a web application (https://rterp.wordpress.com/tag/mxbean/). The truth is that JMX is much more than that.

The core of JMX is MBean’s that are created in your application and can then be manipulated via the JMX framework. The concept of JMX reminds me of the DCOM of Microsoft architecture and CORBA (see https://jcp.org/en/jsr/detail?id=70 for a bridge between the two). In essence you create an MBean on the server (in the MBeanServer), and you can then access this information from any other machine.

The objects in JMX are organized in an ObjectName, which is a tree hierarchy of names. This concept is actually very similar to the SNMP MIB structure.

JMX supports attributes, operations and notifications. I have seen companies build full infrastructures of application monitoring on top of JMX (including synchronizing information between machines via JMX). Since you have attributes you can save state within the MBean. With the operations you can have method actions externalized, and with the notification you can have external client register for events without the hassle of creating a message bus or structure for notification (of course spring support of all JMX functionality: http://docs.spring.io/spring-integration/docs/2.0.0.RC1/reference/html/jmx.html).

Since the concept of the JMX is very open, multiple adapters have been created around the JMX ecosystem.  Java comes with the JConsole application, so you can easily manage your MBeans even remotely. There are HTML adapters, and even SNMP adapters. So if you have a center of data that you need to share with multiple clients in multiple formats you should have a look at JMX:




If you need export you data from JMX to other platforms (like GraphIte  or Gangila) there is a nice package called JMXTrans that comes with some build in  writers and a framework to create new ones (

If all you need is to pass the information over http protocol that you can have a look at jolokia (http://www.jolokia.org/).  

Since is seems for some there is confusion between the two frameworks, both authors answered in the following question on the stackoverflow site: http://stackoverflow.com/questions/10151536/what-is-the-difference-between-jolokia-jmxtrans-when-to-choose-one-over-the


MXBean

Any class can be added to the JMX MBeanServer. If all the external actions (attributes, operations, notifications) use basic java types then you have no problem. You can use a self-written class, though the reading client must have this class in its classpath – a big constraint. To solve this issue JMX added the MXBean (http://docs.oracle.com/javase/7/docs/api/javax/management/MXBean.html) to support “open” types of java objects.

Oracle: An MXBean is a type of MBean that references only a predefined set of data types.
In other words by constraining the data types of you bean, JMX can now translate you “private classes” to a generic format using CompositeData and TabularData classes.

To use an MXBean you either implement an interface with MXBean suffix or use the @MXBean annotation. The other constraint of MXBean is that you must add the annotation @ConstructorProperties to your constructors.

When you use a concrete class in your code the MBeanServer will serialize the class into a generic class of the types:  CompositeData (http://docs.oracle.com/javase/7/docs/api/javax/management/openmbean/CompositeData.html), TabularData http://docs.oracle.com/javase/7/docs/api/javax/management/openmbean/TabularData.html.

These classes are similar to a hashmap, though they include information as to the type of each field. This way and client that supports the JMX MXBean can serialize this object and use it. If your client has your propriety class then you can easily serialize the MXBean back to your class.

The MBeanServer will validate the field types of all MXBean’s to make sure you did not use invalid types. Since you can externalize complex classes, the MXBeanServer will serialize it to one of the classes in the javax.management.openmbean package.

For most cases you do not need to add any special code, since one the MXBean is registered in the MBeanServer any access to this server via a client, the server will property serialize the class. The only case that you need to write code is the case of notification and using the user data object.

Notifications

To send a broadcast notification you create the Notification Object (http://docs.oracle.com/javase/tutorial/jmx/notifs/) The notification object has some basic field like type, source, message and other fields. If you want to add your own typed payload you need to use the User Data object. For complex classes you should be using the CompositeData or the TabularData. 

To create this class you need to specify all the fields and their types, for example:
String[] names = {"poolName", "usage", "count" };
Object[] values = { null, null, null };
OpenType[] types = { SimpleType.STRING, memoryUsageCompositeType,
            SimpleType.LONG };
CompositeType compositeType = getCompositeType(names, types);
CompositeData data = new CompositeDataSupport(compositeType, names, values);

This is obviously not very type safe or developer oriented. The class we would like to use would be like:
public class PoolUsage {
       String poolName;
       MemoryUsage usage;
       Integer count;
}

To solve this issue we will use a trick with the MBeanServer. As stated above if your class is an attribute or used in an operation the MBeanServer will do all the transformations for you. The problem is in the User Data scenario where you need to manually add the class. The trick is to have a helper class that inherits from StandardMBean. This class will have an internal field with your typed class. The trick is then when you want to serialize your class, you create the help class, assign the field with the value and the get the same field but via the getAttribute of the StandardMBean. This way the JMX framework will do the serialization for you. The other direction is the same. You create the helper class and assign the field using the JMX setAttribute (setting the composite data you got in the notification) and the retrieve the specific class using the standard getter.

Sample code:

public class PoolUsageSerializer extends StandardMBean implements PoolUsageInterface{
       private final static String ATTRIBUTE_NAME = "PoolUsage";
       protected PoolUsage poolUsage;

       public PoolUsage getPoolUsage() { return poolUsage;    }

       public void setPoolUsage(PoolUsage poolUsage) { this.poolUsage = poolUsage; }

       public PoolUsageSerializer() { super(PoolUsageInterface.class, true); }


       public static Object serialize(PoolUsage poolUsage) {
              PoolUsageSerializer me = new PoolUsageSerializer();
              me.setPoolUsage(data);
              return me.getAttribute(ATTRIBUTE_NAME);
       }

       public static PoolUsage deserialize(Object userData) {
              PoolUsageSerializer me = new PoolUsageSerializer();
              Attribute attr = new Attribute(ATTRIBUTE_NAME, userData);
              me.setAttribute(attr);
              return me.getPoolUsage();
       }
}

For more information see:

Security

JMX also supports the option to secure the server with user name and password. You can also assign roles (read/write) per user, and even secure communications via ssl. For securing your JMX on tomcat see http://tomcat.apache.org/tomcat-7.0-doc/monitoring.html.