Java Dynamic Management Kit 5.1 Tutorial

8.3 Attribute Change Notifications

In this second part of the notification example, we demonstrate attribute change notifications that can be sent by MBeans. An MBean designer can choose to send notifications whenever the value of an attribute changes or is changed. The designer can implement this mechanism in any manner, according to the level of consistency required by the management solution.

The JMX specification only provides a subclass of notifications to use to represent the attribute change events: the AttributeChangeNotification class.

8.3.1 NotificationBroadcasterSupport Class

The broadcaster in our example is a very simple MBean. The reset method triggers a notification whenever it is called. This policy is specific to our example. You might want to design an MBean that sends an attribute change every time the setter is called, regardless of whether or not the value is modified. Your management needs might vary.

Example 8–3 shows the code for our SimpleStandard MBean class (the code for its MBean interface has been omitted).


Example 8–3 Broadcaster for Attribute Change Notifications

import javax.management.NotificationBroadcasterSupport;
import javax.management.MBeanNotificationInfo;
import javax.management.AttributeChangeNotification;

public class SimpleStandard
    extends NotificationBroadcasterSupport
    implements SimpleStandardMBean {

    public String getState() {
        return state;
    }

    public void setState(String s) {
        state = s;
        nbChanges++;
    }

    [...]
   
    public int getNbChanges() {
        return nbChanges;
    }

    public void reset() {
	         AttributeChangeNotification acn =
	             new AttributeChangeNotification(this,
					                                0,
					                                0,
					                                "NbChanges reset",
					                                "NbChanges",
					                                "Integer",
					                                new Integer(nbChanges),
					                                new Integer(0));
	         state = "initial state";
          nbChanges = 0;
	         nbResets++;
	         sendNotification(acn);
    }    

   public int getNbResets() {
       	return nbResets;
   }

   public MBeanNotificationInfo[] getNotificationInfo() {
        return new MBeanNotificationInfo[] {
	          new MBeanNotificationInfo(
	          new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE },
	          AttributeChangeNotification.class.getName(),
	          "This notification is emitted when the reset() method is 
            called.")
	   };
   
    private String      state = "initial state";
    private int         nbChanges = 0;
    private int         nbResets = 0;
}

This MBean sends its notifications and it implements the NotificationBroadcaster interface by extension of the NotificationBroadcasterSupport class, in order to provide all the mechanisms for adding and removing listeners and sending notifications. It manages an internal list of listeners and their handback objects and updates this list whenever listeners are added or removed. In addition, the NotificationBroadcasterSupport class provides the sendNotification method to send a notification to all listeners currently on its list.

By extending this object, our MBean inherits all of this behavior. Subclassing NotificationBroadcasterSupport is a quick and convenient way to implement notification broadcasters. We do not even have to call a superclass constructor because it has a default constructor. We only need to override the getNotificationInfo method to provide details about all of the notifications that might be sent.

8.3.2 Attribute Change Listener

Like our listener for MBean server notifications, our listener for attribute change notifications is a trivial class consisting of just the handler method.


Example 8–4 Listener for Attribute Change Notifications

import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.AttributeChangeNotification;

public class SimpleStandardListener implements NotificationListener {
    [...]

    // Implementation of the NotificationListener interface
    //
    public void handleNotification(Notification notification,
                                   Object handback) {

        // Process the different types of notifications fired by the
        // simple standard MBean.
        String type = notification.getType();

        System.out.println(
            "\n\t>> SimpleStandardListener received notification:" +
            "\n\t>> ---------------------------------------------");
        try {
            if (type.equals(AttributeChangeNotification.ATTRIBUTE_CHANGE)) {

  System.out.println("\t>> Attribute \"" +
      ((AttributeChangeNotification)notification).getAttributeName()
      + "\" has changed");
  System.out.println("\t>> Old value = " +
      ((AttributeChangeNotification)notification).getOldValue());
  System.out.println("\t>> New value = " +
      ((AttributeChangeNotification)notification).getNewValue());

            }                
            else {
                System.out.println("\t>> Unknown event type (?)\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

Again, we are handling a subclass of the Notification class, this one specific to attribute change notifications. The AttributeChangeNotification class provides methods for extracting the information about the attribute, notably its name, its type and its values before and after the modification. Our handler does nothing more than display these to the user. If this handler were part of an MBean in a larger management solution, it would probably take some action, depending upon the change in value of the attribute.

As demonstrated by the broadcaster's code (see Example 8–3), the subclass can easily be instantiated and sent instead of a Notification object. Its constructor provides parameters for initializing all of the attribute-related values. In our example, we do not use significant values for the sequenceNumber and timeStamp parameters because our listener has no need for them. One great advantage of Java DMK is that you only need to implement the level of functionality that you require for your management solution.


8.3.3 Adding a Listener Directly to an MBean

There is nothing that statically indicates that our MBean sends attribute change notifications. In our case it is a design decision, meaning that we know that the listener will receive attribute change notifications because we wrote the MBean that way. At runtime, the MBean server exposes the list of notifications in this MBean's metadata object, allowing a manager that is interested in attribute changes to register the appropriate listener.

Being confined to the agent, our example is much simpler. First we instantiate and register our simple MBean with the agent's MBean server. Then, because we have designed them to work together, we can add our listener for attribute changes to our MBean by calling the addNotificationListener method on the MBean server.


Example 8–5 Registering for Attribute Change Notifications

Agent myAgent = new Agent();
AgentListener agentListener = null;
SimpleStandard simpleStd = null;
ObjectName simpleStdObjectName = null;
SimpleStandardListener simpleStdListener = null;

[...]
try {
    simpleStdObjectName =
        new ObjectName("simple_mbean:class=SimpleStandard");
    simpleStd = new SimpleStandard();
    myAgent.server.registerMBean(simpleStd, simpleStdObjectName);
} catch(Exception e) {
    e.printStackTrace();
    System.exit(1);
}

echo("\nRegistering the Simple Standard MBean listener...");
try {
     simpleStdListener = new SimpleStandardListener();
     myAgent.server.addNotificationListener(simpleStdObjectName,
                                            simpleStdListener,
                                            null,
                                            null);
} catch (Exception e) {
     e.printStackTrace();
     System.exit(1);
}
echo("done");

There are two major implications when adding listeners directly rather than doing so using the MBean server:

The rest of the agent object's code performs the setup of the agent's MBean server and various input and output for running the example. Similar agents are presented in detail earlier in Part II.