Java Dynamic Management Kit 4.2 Tutorial

Chapter 3 Model MBeans

A model MBean is a generic, configurable MBean which applications can use to instrument any resource dynamically. It is a dynamic MBean that has been implemented so that its management interface and its actual resource can be set programmatically. This allows any manager connected to a Java Dynamic Management agent to instantiate and configure a model MBean on the fly.

Model MBeans allow management applications to make resources manageable at runtime. The managing application must provide a compliant management interface for the model MBean to expose. It must also specify the target objects that actually implement the resource. Once it is configured, the model MBean will pass any management requests to the target objects and handle the result.

In addition, the model MBean provides a set of mechanisms for how management requests and their results are handled. For example, caching can be performed on attribute values. The management interface of a model MBean is augmented by descriptors which contain attributes for controlling these mechanisms.

The code samples in this topic are taken from the files in the ModelMBean example directory in the main examplesDir (see "Directories and Classpath" in the preface).

Contents:

The RequiredModelMBean Class

The required Model MBean is mandated by the JMX specification for all compliant implementations. It is a dynamic MBean which lacks any predefined management interface. It contains a generic implementation which will transmit management request on it management interface to the target objects that define its managed resource.

The name of the required model MBean class is the same for all JMX-compliant implementation. Its full package and class name is javax.management.modelmbean.RequiredModelMBean. By instantiating this class, any application may use model MBeans.

In order to be useful, the instance of the required model MBean must be given a management interface and the target object of the management resource. In addition, the model MBean metadata must contain descriptors for configuring how the model MBean will respond to management requests. We will cover these steps in subsequent sections.

The MBean server does not make any special distinction for model MBeans. Internally they are treated as the dynamic MBeans that they are, and all of the model MBean's internal mechanisms and configurations are completely transparent to a management application. Like all other managed resources in the MBean server, the resources available through the model MBean can only be accessed through the attributes and operations defined in the management interface.

Model MBean Metadata

The metadata of a any MBean is the description of its management interface. The metadata of the model MBean is described by an instance of the ModelMBeanInfo class, which extends the MBeanInfo class.

Like all other MBeans, the metadata of a model MBean contains the list of attributes, operations, constructors, and notifications of the management interface. Model MBeans also describe their target object and their policies for accessing the target object. This information is contained in an object called a descriptor, defined by the Descriptor interface and implemented in the DescriptorSupport class.

There is one overall descriptor for a model MBean instance and one descriptor for each element of the management interface, that is for each attribute, operation, constructor, and notification. Descriptors are stored in the metadata object. As defined by the JMX specification all, of the classes for describing elements are extended so that they contain a descriptor. For example, the ModelMBeanAttributeInfo extends the MBeanAttributeInfo and defines the methods getDescriptor and getDescriptor.

A descriptor is a set of named field and value pairs. Each type of metadata element has a defined set of fields that are mandatory, and users are free to add others. The field names reflect the policies for accessing target objects, and their values determine the behavior. For example the descriptor of an attribute contains the fields currencyTimeLimit and lastUpdatedTimeStamp which are used by the internal caching mechanism when performing a get or set operation.

In this way, model MBeans are manageable as any other MBean, but applications which are aware of model MBeans may interact with the additional features which they provide. The JMX specification defines the names of all required descriptor fields for each of the metadata element, and for the overall descriptor. The field names are also documented in the Javadoc API for the ModelMBean*Info classes.

In our example, our application defines a subroutine to build all descriptors and metadata objects which are needed to define the management interface of the model MBean.


Example 3-1 Defining Descriptors and MBeanInfo Objects

private void buildModelMBeanInfo(
                 ObjectName inMbeanObjectName, String inMbeanName) {
  try {

    // Create the descriptor and ModelMBeanAttributeInfo
    // for the 1st attribute
    //
    Descriptor stateDesc = new DescriptorSupport();
    stateDesc.setField("name","State");
    stateDesc.setField("descriptorType","attribute");
    stateDesc.setField("displayName","MyState");
    stateDesc.setField("getMethod","getState");
    stateDesc.setField("setMethod","setState");
    stateDesc.setField("currencyTimeLimit","20");

    dAttributes[0] = new ModelMBeanAttributeInfo(
                             "State",
                             "java.lang.String",
                             "State: state string.",
                             true,
                             true,
                             false,
                             stateDesc);

    [...] // create descriptors and ModelMBean*Info for
          // all attributes, operations, constructors
          // and notifications

    // Create the descriptor for the whole MBean
    //
    mmbDesc = new DescriptorSupport( new String[] 
                      { ("name="+inMbeanObjectName),
                        "descriptorType=mbean",
                        ("displayName="+inMbeanName),
                        "log=T",
                        "logfile=jmxmain.log",
                        "currencyTimeLimit=5"});

    // Create the ModelMBeanInfo for the whole MBean
    // 
    private String dClassName = "TestBean";
    private String dDescription =
       "Simple implementation of a test app Bean.";

    dMBeanInfo = new ModelMBeanInfoSupport(
                         dClassName,
                         dDescription,
                         dAttributes,
                         dConstructors,
                         dOperations,
                         dNotifications);

    dMBeanInfo.setMBeanDescriptor(mmbDesc);

  } catch (Exception e) {
    echo("\nException in buildModelMBeanInfo : " +
          e.getMessage());
    e.printStackTrace();
  }
}

The Target Object(s)

The object instance which actually embodies the behavior of the managed resource is called the target object. The last step of creating a model MBean is to give the MBean skeleton and its defined management interface a reference to the target object. Thereafter, management requests can be handled by model MBean, which will forward them to the target object and handle the response.

The following code example implements the TestBean class which is the simple managed resource in our example. Its methods provide the implementation for two attributes and one operation.


Example 3-2 Implementing the Managed Resource

public class TestBean 
   implements java.io.Serializable
{

    // Constructor
    //
    public TestBean() {
        echo("\n\tTestBean Constructor Invoked: State " + 
             state + " nbChanges: " + nbChanges +
             " nbResets: " + nbResets);

    }

    // Getter and setter for the "State" attribute
    //
    public String getState() {
        echo("\n\tTestBean: getState invoked: " + state);
        return state;
    }

    public void setState(String s) {
        state = s;
        nbChanges++;
        echo("\n\tTestBean: setState to " + state +
             " nbChanges: " + nbChanges);
    }


    // Getter for the read-only "NbChanges" attribute
    //
    public Integer getNbChanges() {
        echo("\n\tTestBean: getNbChanges invoked: " + nbChanges);
        return new Integer(nbChanges);
    }

    // Method of the "Reset" operation
    //
    public void reset() {
        echo("\n\tTestBean: reset invoked ");
        state = "reset initial state";
        nbChanges = 0;
        nbResets++;
    }

    // Other public method; looks like a getter,
    // but no NbResets attribute is defined in
    // the management interface of the model MBean
    //
    public Integer getNbResets() {
        echo("\n\tTestBean: getNbResets invoked: " + nbResets);
        return new Integer(nbResets);
    }

    // Internals
    //
    private void echo(String outstr) {
        System.out.println(outstr);
    }

    private String  state = "initial state";
    private int     nbChanges = 0;
    private int     nbResets = 0;

}

By default, the model MBean handles a managed resource that is contained in one object instance. This target is specified through the setManagedResource method defined by the ModelMBean interface. The resource can encompass several programmatic objects because individual attributes or operations can be handled by different target objects. This behavior is configured through the optional targetObject and targetType descriptor fields of each attribute or operation.

In our example, one of the operations is handled by an instance of the TestBeanFriend class. In the definition of this operation's descriptor, we set this instance as the target object. We then create the operation's ModelMBeanOperationInfo with this descriptor and add it to the list of operations in the metadata for our model MBean.


Example 3-3 Setting Other Target Objects

MBeanParameterInfo[] params = null;

Descriptor getNbResetsDesc = new DescriptorSupport(new String[]
                                    { "name=getNbResets",
                                      "class=TestBeanFriend",
                                      "descriptorType=operation",
                                      "role=operation"});
                                      
TestBeanFriend tbf = new TestBeanFriend();
getNbResetsDesc.setField("targetObject",tbf);
getNbResetsDesc.setField("targetType","objectReference");

dOperations[1] = new ModelMBeanOperationInfo(
                         "getNbResets",
                "getNbResets(): get number of resets performed",
                         params ,
                         "java.lang.Integer",
                         MBeanOperationInfo.INFO,
                         getNbResetsDesc);

Creating the Model MBean

In order to insure coherence in an agent application, you should define the target object of an MBean before you expose it for management. This implies that you should call the setManagedResource method before registering the model MBean in the MBean server.

The following code example show how our application creates the model MBean. First it calls the subroutine give in Example 3-1 to build the descriptors and management interface of our model MBean. Then it instantiates the required model MBean class with this metadata. Finally it creates and sets the managed resource object before registering the model MBean.


Example 3-4 Setting the Default Target Object

ObjectName mbeanObjectName = null;
String domain = server.getDefaultDomain();
String mbeanName = "ModelSample";

try
{
     mbeanObjectName = new ObjectName(
                               domain + ":type=" + mbeanName);
} catch (MalformedObjectNameException e) {
     e.printStackTrace();
     System.exit(1);
}

// Create the descriptors and ModelMBean*Info objects
// of the management interface
//
ModelMBeanInfo dMBeanInfo = null;
buildModelMBeanInfo( mbeanObjectName, mbeanName );

try {
    // Instantiate javax.management.modelmbean.RequiredModelMBean
    RequiredModelMBean modelmbean =
        new RequiredModelMBean( dMBeanInfo );

    // Associate it with the resource (a TestBean instance)
    modelmbean.setManagedResource( new TestBean(), "objectReference");

    // register the model MBean in the MBean server
    server.registerMBean( modelmbean, mbeanObjectName );

} catch (Exception e) {
     echo("\t!!! ModelAgent: Could not create the model MBean !!!");
     e.printStackTrace();
     System.exit(1);
}

Our model MBean is then available for management operations and remote requests, just like any other registered MBean.


Running the Model MBean Example

The examplesDir/ModelMBean directory contains the TestBean.java file which is the target object of the sample model MBean. This directory also contains a simple notification listener class and the agent application, ModelAgent, which instantiates, configures and manages a model MBean.

The model MBean itself is given by the RequiredModelMBean class defined in the javax.management.modelmbean package provided in the runtime jar file (jdmkrt.jar) of the Java Dynamic Management Kit.

Compile all files in this directory with the javac command. For example, on the Solaris platform, you would type:


$ cd examplesDir/ModelMBean/
$ javac -classpath classpath *.java

To run the example, launch the agent class with the following command:


$ java -classpath classpath ModelAgent

Type return when the application pauses to step through the example. The agent application handles all input and output in this example and gives us a view of the MBean at runtime.

We can then see the result of managing the resource through its exposed attributes and operations. The agent also instantiates and registers a listener object for attribute change notifications sent by the model MBean. You can see the output of this listener whenever it receives a notification, after the application has called one of the attribute setters.