Instrumenting Resources as Model MBeans

In this chapter, we have seen how to create Descriptor objects and the necessary metadata classes for a model MBean, and we have looked at RequiredModelMBean and the interfaces that it must implement. In this section, we will see how to tie all of this information together to instrument resources as model MBeans.

The steps you must go through to instrument each of your resources as model MBeans are:

  1. Create an instance of the resource to be managed.

  2. Create an instance of RequiredModelMBean.

  3. Create the necessary metadata classes and optional descriptors for the features of the management interface.

  4. Create the metadata for the resource (i.e., the ModelMBeanInfo object).

  5. Set the metadata of RequiredModelMBean to the metadata for the resource (from Step 3) and the resource to be managed through the ModelMBean interface.

As in the previous chapters, we will use the sample application for all of our examples. This will allow you to compare and contrast the other MBean types with model MBeans.

In the examples presented here we will look at the application class Controller, which acts as the JMX agent. For the example code in this chapter, the Controller class is responsible for creating the resources to be managed, instrumenting them as model MBeans, and registering them with the MBean server.

The first two steps are to create an instance of the managed resource (in this example, the Queue) and to create the RequiredModelMBean instance:

// . . .
Queue queue = new Queue(  );
RequiredModelMBean queueModelMBean = new RequiredModelMBean(  );
// . . .

Next, we must create the necessary model MBean metadata classes (only some of the attributes and operations are shown, as the examples can be quite lengthy). First we’ll create the attributes:

// There are 10 attributes . . .
ModelMBeanAttributeInfo[] attributeInfo = new ModelMBeanAttributeInfo[10];
attributeInfo[0] = new ModelMBeanAttributeInfo(
  "QueueSize",
  "java.lang.Integer",
  "The maximum size of the queue.",
  true,
  true,
  false,
);
DescriptorSupport desc = attributeInfo[0].getDescriptor(  );
desc.setField("getMethod", "getQueueSize");
desc.setField("setMethod", "setQueueSize");
desc = new DescriptorSupport(
  new String[] {
    "name=NumberOfItemsProcessed",
    "descriptorType=attribute",
    "getMethod=getNumberOfItemsProcessed",
  }
);
attributeInfo[1] = new ModelMBeanAttributeInfo(
  "NumberOfItemsProcessed",
  "java.lang.Long",
  "The number of work units processed.",
  true,
  false,
  false,
);
// . . . other attributes . . .
desc = new DescriptorSupport(
  new String[] {
    "name=NumberOfConsumers",
    "descriptorType=attribute",
    "getMethod=getNumberOfConsumers",
  }
);
attributeInfo[9] = new ModelMBeanAttributeInfo(
  "NumberOfConsumers",
  "java.lang.Integer",
  "No. of consumer threads currently feeding the queue.",
  true,
  false,
  false,
);

Then we’ll create the metadata for the operations:

// . . .
ModelMBeanOperationInfo[] operationInfo = new ModelMBeanOperationInfo[13];
desc = new DescriptorSupport(
  new String[] {
    "name=suspend",
    "descriptorType=operation",
    "role=operation",
  }
);
operationInfo[0] = new ModelMBeanOperationInfo(
  "suspend",
  "Suspends activity in the queue.",
  new MBeanParameterInfo[0],
  Void.TYPE.getName(  ),
  MBeanOperationInfo.ACTION,
);
desc = new DescriptorSupport(
  new String[] {
    "name=resume",
    "descriptorType=operation",
  }
);
operationInfo[1] = new ModelMBeanOperationInfo(
  "resume",
  "Resumes activity in the queue.",
  new MBeanParameterInfo[0],
  Void.TYPE.getName(  ),
  MBeanOperationInfo.ACTION,
  desc
);
// . . .

One difference between model MBeans and other MBean types is that operation metadata must be created for attribute getters and setters. This is probably an oversight of the JMX RI, but one that you must deal with if you wish to use it. For each getter and setter, you must create a ModelMBeanOperationInfo instance, such that a writable attribute has two ModelMBeanOperationInfo instances (one for the getter and one for the setter). A read-only attribute will have only one (for the getter). The following example shows how to create the ModelMBeanOperationInfo objects for the getters and setters for the attributes for Queue. Note that only QueueSize has a setter.

// . . .
desc = new DescriptorSupport(
  new String[] {
    "name=getQueueSize",
    "descriptorType=operation",
    "role=getter"
  }
);
operationInfo[2] = new ModelMBeanOperationInfo(
  "getQueueSize",
  "Getter for QueueSize",
  new MBeanParameterInfo[0],
  Integer.TYPE.getName(  ),
  MBeanOperationInfo.INFO,
  desc
);
desc = new DescriptorSupport(
  new String[] {
    "name=setQueueSize",
    "descriptorType=operation",
    "role=setter"
  }
);
MBeanParameterInfo[] parms = new MBeanParameterInfo[1];
parms[0] = new MBeanParameterInfo(
  "value",
  "java.lang.Integer",
  "value"
);
operationInfo[3] = new ModelMBeanOperationInfo(
  "setQueueSize",
  "Setter for QueueSize",
  parms,
  Void.TYPE.getName(  ),
  MBeanOperationInfo.ACTION,
  desc
);
// . . . other getters. ..
desc = new DescriptorSupport(
  new String[] {
    "name=getNumberOfSuppliers",
    "descriptorType=operation",
    "role=getter"
  }
);
// . . .other getters/setters. . .
operationInfo[12] = new ModelMBeanOperationInfo(
  "getNumberOfSuppliers",
  "Getter for NumberOfSuppliers",
  new MBeanParameterInfo[0],
  Integer.TYPE.getName(  ),
  MBeanOperationInfo.INFO,
  desc
);

Because no explicit constructors are required and there are no notifications, the ModelMBeanInfo object can be created:

// . . .
  ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(
    queue.getClass().getName(  ),
    "Queue Model MBean",
    attributeInfo,
    null,
    operationInfo,
    null
  );
  queueModelMBean.setModelMBeanInfo(mbeanInfo);
  queueModelMBean.setManagedResource(queue, "ObjectReference");
  MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(  );
  mbeanServer.registerMBean(queueModelMBean, objName);
// . . .

Notice the emphasized line in this example. The managed resource isn’t the instance of RequiredModelMBean (whose instance variable is queueModelMBean), but the instance of the Queue (whose instance variable is queue). When we were creating standard and dynamic MBeans, the managed resource and the MBean were physically the same object. Although they are logically still one entity, with model MBeans the managed resource and the MBean (i.e., the instance of RequiredModelMBean) are not physically the same object.

In creating the metadata for the model MBean itself, we have allowed the ModelMBeanInfoSupport constructor to create a default descriptor. If you would like to create a descriptor for the ModelMBeanInfo object that represents your MBean, there should be sufficient information in this chapter to help you do that.

Notice that we can pass null as parameter values for the constructors and notification metadata (we can also pass null for attribute or operation metadata if there are no attributes or operations, respectively). In previous sections (and the previous chapter), we covered at length how to create constructor and notification metadata. If you need to create these metadata classes, simply pass them as the appropriate parameters to the ModelMBeanInfoSupport constructor.

Get Java Management Extensions now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.