Java Dynamic Management Kit 5.1 Tutorial

Chapter 3 Model MBeans

A model MBean is a generic, configurable MBean that 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 enables any manager connected to a Java dynamic management agent to instantiate and configure a model MBean dynamically.

Model MBeans enable 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 passes any management requests to the target objects and handles 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 that contain attributes for controlling these mechanisms.

The code samples in this chapter are taken from the files in the ModelMBean example directory in the main examplesDir/current directory (see “Directories and Classpath” in the Preface).

This chapter covers the following topics:

3.1 RequiredModelMBean Class

The required model MBean is mandated by the Java Management Extensions (JMX) specification for all compliant implementations. It is a dynamic MBean that lacks any predefined management interface. It contains a generic implementation that transmits management requests on its 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 implementations. Its full package and class name is javax.management.modelmbean.RequiredModelMBean. By instantiating this class, any application can 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.

3.2 Model MBean Metadata

The metadata of an 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 classes for describing elements are extended so that they contain a descriptor. For example, the ModelMBeanAttributeInfo class extends the MBeanAttributeInfo class and defines the methods getDescriptor and setDescriptor.

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 that are used by the internal caching mechanism when performing a get or set operation.

In this way, model MBeans are manageable in the same way as any other MBean, but applications that are aware of model MBeans can interact with the additional features they provide. The JMX specification defines the names of all required descriptor fields for each of the metadata elements and for the overall descriptor. The field names are also described in the API documentation generated by the Javadoc tool for the ModelMBean*Info classes.

In Example 3–1 , the application defines a subroutine to build all descriptors and metadata objects needed to define the management interface of the model MBean.


Example 3–1 Defining Descriptors and MBeanInfo Objects

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

    // Create the descriptor and ModelMBeanAttributeInfo
    // for the 1st attribute
    //
    mmbDesc = new DescriptorSupport( new String[] 
                      { ("name="+inMbeanObjectName),
                        "descriptorType=mbean",
                        ("displayName="+inMbeanName),
                        "log=T",
                        "logfile=jmxmain.log",
                        "currencyTimeLimit=5"});
    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


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

    dMBeanInfo.setMBeanDescriptor(mmbDesc);

  } catch (Exception e) {
    echo("\nException in buildModelMBeanInfo : " +
          e.getMessage());
    e.printStackTrace();
  }
    // Create the ModelMBeanInfo for the whole MBean
    // 
    private String dClassName = "TestBean";
    private String dDescription =
    "Simple implementation of a test app Bean.";
}

3.3 Target Object(s)

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

Example 3–2 implements the TestBean class that 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 Example 3–3, 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);

3.4 Creating a Model MBean

To ensure 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.

Example 3–4 shows how our application creates the model MBean. First it calls the subroutine given in Example 3–1 to build the descriptors and management interface of the 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
//
buildDynamicMBeanInfo( mbeanObjectName, mbeanName );

try {
    RequiredModelMBean modelmbean =
        new RequiredModelMBean( dMBeanInfo );
    // Set the managed resource for the ModelMBean 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 " + mbeanName +
                 " MBean !!!");
     e.printStackTrace();
     System.exit(1);
}

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

3.5 Running the Model MBean Example

The examplesDir/current/ModelMBean directory contains the TestBean.java file that 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 (jmx.jar) of the Java Dynamic Management Kit (Java DMK).

To Run the Model MBean Example
  1. Compile all files in this directory with the javac command.

    For example, on the Solaris platform, type:


    $ cd examplesDir/current/ModelMBean/
    $ javac -classpath classpath *.java
    
  2. To run the example, start the agent class with the following command:


    $ java -classpath classpath ModelAgent
    
  3. Press Enter when the application pauses to step through the example.

    The agent application handles all input and output in this example and gives 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.