Contents | Previous | Next | Java Management Extensions (JMX) Technology Tutorial

## Chapter 2

## Essentials of the JMX API

This chapter introduces the fundamental notion of the Java Management Extensions (JMX) API, namely managed beans, or MBeans.

An MBean is a managed Java object, similar to a JavaBeanTM, that follows the design patterns set forth in the instrumentation level of the JMX specification. An MBean can represent a device, an application, or any resource that needs to be managed. MBeans expose a management interface: a set of readable and/or writable attributes and a set of invokable operations, along with a self-description. The management interface does not change throughout the life of an MBean instance. MBeans can also emit notifications when certain defined events occur.

The JMX specification defines four types of MBean: standard MBeans, dynamic MBeans, open MBeans and model MBeans. The examples in this chapter demonstrate the simplest type of MBean, namely standard MBeans.

## 2.1 Standard MBeans

A standard MBean is defined by writing a Java interface called `SomethingMBean` and a Java class called `Something` that implements that interface. Every method in the interface defines either an attribute or an operation in the MBean. By default every method defines an operation. Attributes and operations are simply methods which follow certain design patterns. A standard MBean is composed of the MBean interface which lists the methods for all exposed attributes and operations, and the class which implements this interface and provides the functionality of the instrumented resource.

The following sections dissect an example standard MBean, and a simple JMX agent that manages the MBean. The code samples are taken from the directory work_dir`/jmx_examples/Essential/com/example/mbeans.`

### 2.1.1 MBean Interface

An example of a very basic MBean interface, named `HelloMBean`, is shown in CODE EXAMPLE 2-1.

CODE EXAMPLE 2-1 Example MBean Interface, HelloMBean

    package com.example.mbeans;

    public interface HelloMBean {

        public void sayHello();
        public int add(int x, int y);

        public String getName();

        public int getCacheSize();
        public void setCacheSize(int size);
    }

As stated previously, by convention an MBean interface takes the name of the Java class that implements it, with the suffix MBean added. So, in this case, the interface is called `HelloMBean`. The `Hello` class that implements this interface is described in Section 2.1.2 "MBean Implementation".

According to the JMX specification, an MBean interface consists of named and typed attributes that are readable and possibly writable, and named and typed operations that can be invoked by the applications that are managed by the MBean. The `HelloMBean` interface shown in CODE EXAMPLE 2-1, declares two operations: the Java methods `add()` and `sayHello()`.

Of the two attributes that are declared by `HelloMbean`, `Name` is a read-only string, and `CacheSize` is an integer that can be both read and written. Getter and setter methods are declared, to allow the managed application to access and possibly change the attribute values. As defined by the JMX specification, a getter is any public method whose name begins with get and which does not return void. A getter enables a manager to read the value of the attribute, whose type is that of the returned object. A setter is any public method whose name begins with set and which takes a single parameter. A setter enables a manager to write a new value in the attribute, whose type is the same as that of the parameter.

The implementation of these operations and attributes is shown in the following section.

### 2.1.2 MBean Implementation

The `Hello` class shown in CODE EXAMPLE 2-2 implements `HelloMBean`.

CODE EXAMPLE 2-2 Example MBean Implementation Class, Hello

    package com.example.mbeans;

    public class Hello implements HelloMBean {
        public void sayHello() {
    	System.out.println("hello, world");
        }

        public int add(int x, int y) {
    	return x + y;
        }

        public String getName() {
    	return this.name;
        }

        public int getCacheSize() {
    	return this.cacheSize;
        }

        public synchronized void setCacheSize(int size) {
    	this.cacheSize = size;

    	System.out.println("Cache size now " + this.cacheSize);
        }

        private final String name = "Reginald";
        private int cacheSize = DEFAULT_CACHE_SIZE;
        private static final int DEFAULT_CACHE_SIZE = 200;
    }

The straightforward Java class `Hello` provides the definitions of the operations and attributes declared by `HelloMBean`. As you can see, the `sayHello()` and `add()` operations are extremely simple, but real-life operations can be as simple or as sophisticated as you like.

Methods to get the `Name` attribute and to get and set the `cacheSize` attribute are also defined. In this example, the `Name` attribute value never changes, but in a real scenario it might change as the managed resource runs. For example, the attribute might represent statistics such as uptime or memory usage. Here, it is merely the name “Reginald”.

Calling the `setCacheSize` method allows you to alter the `cacheSize` attribute from its declared default value of 200. In reality, changing the `cacheSize` attribute could require other operations to be performed, such as discarding entries or allocating new ones. This example merely prints a message to confirm that the cache size has changed, but more sophisticated operations could be defined in the place of the simple call to `println()`.

With the simple `Hello` MBean and its interface thus defined, they can now be used to manage the resource they represent, as shown in the following section.

### 2.1.3 Managing a Resource

As presented in the Java Management Extensions (JMX) Technology Overview, once a resource has been instrumented by MBeans, the management of that resource is performed by a JMX agent.

The core component of a JMX agent is the MBean server, a managed object server in which MBeans are registered (see the API documentation for the `MBeanServer` interface for details of the MBean server implementation). A JMX agent also includes a set of services to manage MBeans.

CODE EXAMPLE 2-3 presents a basic JMX agent, named `Main`.

CODE EXAMPLE 2-3 Creating a JMX Agent

    package com.example.mbeans;

    import java.lang.management.*;
    import javax.management.*;

    public class Main {

       public static void main(String[] args) throws Exception {

          MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

          ObjectName name = new ObjectName("com.example.mbeans:type=Hello");

          Hello mbean = new Hello();

          mbs.registerMBean(mbean, name);

          System.out.println("Waiting forever...");
          Thread.sleep(Long.MAX_VALUE);
       }
    }

The JMX agent `Main` begins by obtaining any MBean server that is running on the platform, by calling the `getPlatformMBeanServer()` method of the `java.lang.management.ManagementFactory` class. If there is no MBean server already running on the platform, then `getPlatformMBeanServer()` creates one automatically by calling the JMX method `MBeanServerFactory.createMBeanServer()`. The `MBeanServer` instance obtained by `Main` is named `mbs`.

Next, `Main` defines an object name for the MBean instance it will create. Every JMX MBean must have an object name. The object name is an instance of the JMX class `ObjectName`, and must conform to the syntax defined by the JMX specification, namely it must comprise a domain, and a list of key-properties (see the API documentation for the `ObjectName` class for details of this syntax). In the object name defined by `Main`, `name`, the domain is `com.example.mbeans` (the package in which the example MBeans are contained) and the key-property declares that this object is of the type `Hello`.

An instance of a `Hello` object is created, named `mbean`. This `Hello` object is itself an instance of the MBean `Hello` that was defined in Section 2.1.2 "MBean Implementation".

The `Hello` object named `mbean` is then registered as an MBean in the MBean server `mbs` with the object name `name`, by passing the object and the object name into a call to the JMX method `MBeanServer.registerMBean()`.

With the `Hello` MBean registered in the MBean server, `Main` will simply wait for management operations to be performed on `Hello`. In the scope of this example, these management operations are invoking `sayHello()`, and `add()`, and getting and setting the attribute values.

### 2.1.4 Running the Standard MBean Example

Having examined the example classes, you can now run the example. The Java 2 Platform, Standard Edition (J2SE) version 5.0 comes with a management and monitoring console, named JConsole, that is used to interact with the MBean in this example. JConsole is located in J2SE_HOME`/bin/jconsole`, in which J2SE_HOME is the installation directory of the J2SE platform.

To run the example, follow the steps below, or see the `README` file:

1. If you have not done so already, open work_dir`/jmx_examples/Essential`.

`$` cd work_dir/jmx_examples/Essential

2. Compile the example Java classes.

`$` javac com/example/mbeans/*.java

3. Start the `Main` application and allow local monitoring on the same host.

`$` java -Dcom.sun.management.jmxremote com.example.mbeans.Main

You will see confirmation that `Main` is waiting for something to happen.

4. Start JConsole in a different terminal window on the same machine.

`$` jconsole

You will see the JConsole tool open, presenting a list of running JMX agents that you can connect to.

5. Select `com.example.mbeans.Main` from the list in the “JConsole: Connect to Agent” window, and click on “Connect”.

You will see a summary of your platform’s current activity.

6. Click on the “MBeans” tab.

This panel shows you all the MBeans currently registered in the MBean server.

7. In the left-hand frame, click on the drop-down icon for `com.example.mbeans`.

You will see the example MBean `Hello`, that was created and registered by `Main`.

8. Click on the `Hello` MBean.

This displays the MBean attributes that were defined by the `Hello` class.

9. Change the value of the `CacheSize` attribute to 150

In the terminal window in which you started `Main`, you will see confirmation of this change of attribute.

10. Click on the “Operations” tab.

Here you will see the two operations declared by the `Hello` MBean, `sayHello()` and `add()`.

11. Invoke the `sayHello()` operation, by clicking on the `sayHello` button.

A JConsole dialogue box will inform you that the method was invoked successfully, and you will see the message “hello, world” in the terminal window in which `Main` is running.

12. Provide two integers for the `add()` operation to add up, and click on the `add` button.

You will be informed of the answer in a JConsole dialogue box.

13. Click on the “Info” tab.

The `Hello` MBean’s object name and its implementation class will be displayed.

14. Click on “Connection” and then “Exit”, to exit JConsole.

## 2.2 Sending Notifications

MBeans can generate notifications, for example to signal a state change, a detected event, or a problem.

For an MBean to generate notifications, it must implement the interface `NotificationBroadcaster`, or its subinterface `NotificationEmitter`. All you need to do to send a notification is to construct an instance of the class `javax.management.Notification` or a subclass (such as `AttributeChangedNotification`), and pass it to `NotificationBroadcasterSupport.sendNotification`.

Every notification has a source. The source is the object name of the MBean that emitted the notification.

Every notification has a sequence number. This number can be used to order notifications coming from the same source when order matters and there is a danger of the notifications being handled in the wrong order. It is all right for the sequence number to be zero, but it is better for it to increment for each notification from a given MBean.

There is an example of a standard MBean that emits notifications in the directory work_dir`/jmx_examples/Notification/com/example/mbeans`. This example is essentially the same as the example seen in Section 2.1 "Standard MBeans", except that the `Hello` MBean implements the `NotificationBroadcaster` interface.

### 2.2.1 NotificationBroadcaster Interface

As stated above, the only difference between this example and the one presented in Section 2.1 "Standard MBeans" is the fact that the MBean implementation allows for the sending of notifications.

Notifications are activated by implementing the `NotificationBroadcaster` interface, as shown in CODE EXAMPLE 2-4.

CODE EXAMPLE 2-4 Implementing MBean Notifications

    package com.example.mbeans;

    import javax.management.*;

    public class Hello
            extends NotificationBroadcasterSupport implements HelloMBean {

        public void sayHello() {
            System.out.println("hello, world");
        }

        public int add(int x, int y) {
            return x + y;
        }

        public String getName() {
            return this.name;
        }

        public int getCacheSize() {
            return this.cacheSize;
        }

        public synchronized void setCacheSize(int size) {
            int oldSize = this.cacheSize;
            this.cacheSize = size;

            System.out.println("Cache size now " + this.cacheSize);

            Notification n =
                new AttributeChangeNotification(this,
    					    sequenceNumber++,
    					    System.currentTimeMillis(),
    					    "CacheSize changed",
    					    "CacheSize",
    					    "int",
    					    oldSize,
    					    this.cacheSize);

    	sendNotification(n);
        }

        @Override
        public MBeanNotificationInfo[] getNotificationInfo() {
            String[] types = new String[] {
                AttributeChangeNotification.ATTRIBUTE_CHANGE
            };
            String name = AttributeChangeNotification.class.getName();
            String description = "An attribute of this MBean has changed";
            MBeanNotificationInfo info =
                new MBeanNotificationInfo(types, name, description);
            return new MBeanNotificationInfo[] {info};
        }

        private final String name = "Reginald";
        private int cacheSize = DEFAULT_CACHE_SIZE;
        private static final int DEFAULT_CACHE_SIZE = 200;

        private long sequenceNumber = 1;
    }

As you can see in CODE EXAMPLE 2-4, this `Hello` MBean implementation extends the `NotificationBroadcasterSupport` class, that itself implements the `NotificationEmitter` interface.

The operations and attributes are set in the same way as before, with the only exception that the `cacheSize` attribute’s setter method now defines a new value `oldSize`, which records the `cacheSize` attribute’s value prior to the set operation.

The notification is constructed from an instance, `n`, of the JMX class `AttributeChangeNotification`, which extends `javax.management.Notification`. The notification is constructed within the definition of the `setCacheSize()` method, from the following information, that is passed to `AttributeChangeNotification` as parameters:

- The object name of the source of the notification, namely the `Hello` MBean, represented simply by `this`
- A sequence number, which in this example is a long named `sequenceNumber`, that is set at 1 and that increases incrementally
- A timestamp
- The content of the notification message
- The name of the attribute that has changed, in this case `cacheSize`
- The type of attribute that has changed
- The old attribute value, in this case `oldSize`
- The new attribute value, in this case `this.cacheSize`

The notification n is then passed to the `NotificationBroadcasterSupport.sendNotification()` method.

Finally, the `MBeanNotification` is defined to describe the characteristics of the different notification instances emitted by the MBean for a given Java class of notification, which in this case is `AttributeChangeNotification` notifications.

The MBean interface, `HelloMBean`, and the JMX agent `Main` are identical to those used in the previous example.

### 2.2.2 Running the MBean Notfication Example

Having examined the example classes, you can now run the example. This example again uses JConsole to interact with the `Hello` MBean.To run the example, follow the steps below, or see the `README` file:

1. If you have not done so already, open work_dir`/jmx_examples/Notification`.

`$` cd work_dir/jmx_examples/Notification

2. Compile the example Java classes.

`$` javac com/example/mbeans/*.java

3. Start the `Main` application and allow local monitoring on the same host.

`$` java -Dcom.sun.management.jmxremote com.example.mbeans.Main

You will see confirmation that `Main` is waiting for something to happen.

4. Start JConsole in a different terminal window on the same machine.

`$` jconsole

You will see the JConsole tool open, presenting a list of running JMX agents that you can connect to.

5. Select `com.example.mbeans.Main` from the list in the “JConsole: Connect to Agent” window, and click on “Connect”.

You will see a summary of your platform’s current activity.

6. Click on the “MBeans” tab.

This panel shows you all the MBeans currently registered in the MBean server.

7. In the left-hand frame, click on the drop-down icon for `com.example.mbeans`.

You will see the example MBean `Hello`, that was created and registered by `Main`.

8. Click on the `Hello` MBean.

This displays the MBean attributes that were defined by the `Hello` class.

9. Click on the “Notifications” tab.

You will see that the panel is blank.

10. Click on the “Subscribe” button.

The current number of notifications received (0), will be displayed in the “Notifications” tab header.

11. Click on the “Attributes” tab, and change the value of the `CacheSize` attribute to 150

In the terminal window in which you started `Main`, you will see confirmation of this change of attribute. You will also see that the number of notifications received displayed in the “Notifications” tab header has changed to 1.

12. Click on the “Notifications” tab again.

You will see the details of the notification that was sent.

13. Click on “Connection” and then “Exit”, to exit JConsole.

Contents | Previous | Next | Java Management Extensions (JMX) Technology Tutorial Java Management Extensions (JMX), Java 2 Platform, Standard Edition 5.0

Copyright © 2004 Sun Microsystems, Inc. All rights reserved.