7.1 Timer Service

Many management tasks are schedule driven. Incremental workstation backups are scheduled to take place every morning at 2:00 A.M. Web server logs are collected and aggregated every hour . New content or a new service is scheduled to go online at midnight. The list goes on and on. To help developers and administrators handle scheduled activities, JMX provides a basic timer service.

Instances of the timer service send JMX notifications at specified dates and times. The notifications may be scheduled to occur just once or to recur with a given frequency. The number of times a recurring notification is sent may be specified beforehand, or the notification may continue to recur indefinitely. Management applications react to timer service notifications by listening for them with notification listeners.

The code in Listing 7.1 illustrates the basics of timer service use.

Listing 7.1 A Service That Uses Timer Service to Restart
 RestartingServiceMBean.java  package  net.jnjmx.ch7;  public interface  RestartingServiceMBean {  void  start();  void  stop(); } RestartingService.java package net.jnjmx.ch7; import java.util.Date; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.timer.Timer; public class RestartingService implements RestartingServiceMBean, NotificationListener {   private long tzero = -1;   public RestartingService() {}   /** Start the service and remember the start time    */   public void start() {     if (tzero < 0) {       tzero = System.currentTimeMillis();       System.out.println("Restarted at: " + tzero);     }   }   /** Stop the service if it is running    */   public void stop() {     if (tzero > 0)       tzero = -1;   }   /** Restart the service    */   public void handleNotification(Notification notification, Object hb) {     stop();     start();   }   public static void main(String[] args) throws Exception {     MBeanServer mbs = MBeanServerFactory.createMBeanServer();     // Create a timer service instance and start it     ObjectName ton = new ObjectName("examples:id=RestartTimer");     mbs.createMBean("javax.management.timer.Timer", ton);     mbs.invoke(ton, "start", new Object[] {}, new String[] {});     // Schedule a jnjmx.examples.restart notification every 24 hours     Integer nid = (Integer) mbs.invoke(ton,                                        "addNotification",                                        new Object[] {"jnjmx.examples.restart",                                                      "restart",                                                      null,                                                      tomorrow(),                                                      new Long(Timer.ONE_DAY) },                                        new String[] {"java.lang.String",                                                      "java.lang.String",                                                      "java.lang.Object",                                                      "java.util.Date",                                                      "long" });     // Listen for restart notifications     mbs.addNotificationListener(ton,   new RestartingService(),   null,   new Object());     // If you have something useful to do, do it here ...     Thread.sleep(Timer.ONE_DAY + 7);   }   /** Compute 24 hours from now in milliseconds    */   private static Date tomorrow() {     return new Date(System.currentTimeMillis() + Timer.ONE_DAY);   } } 

To use the timer service we need an instance of it, so we use the MBeanServer's createMBean() method to create and register one. Now we can schedule a notification. We always have to specify the notification type, associated message, user data, and date. The type, message, and user data will be included in the notification that is delivered to listeners at the appointed date. The notification period (the number of milliseconds to delay between recurring notifications) and the number of times the notification is to be sent may be specified as well; if we don't specify how many times to send the notification, it will be sent indefinitely. Finally, each notification is identified by an ID, an integer that uniquely identifies the notification in the context of a given timer service instance.

To listen for the notification we scheduled, we attach an instance of NotificationListener to the timer service instance. When the notification is sent, the listener's handleNotification() method will be invoked with an instance of TimerNotification that encapsulates all of the information associated with the notification when it was scheduled.

7.1.1 The Notification Queue

The JMX timer service is organized around a priority queue of scheduled notifications. Each entry in the queue is an ordered pair consisting of a date and a set of notifications. The queue is prioritized by date so that the earliest ”that is, next chronological ”date is at the head of the queue. Entries are added to the queue via one of the timer service's addNotification() methods . Entries are removed from the queue either by the timer service itself after the notification has been sent the specified number of times, or via one of its removeNotification() methods.

Figure 7.1 illustrates the timer service's use of its notification queue.

Figure 7.1. Notification Queues at Three Points in Time. (a) The notification queue prior to 8:30 A.M., April 14, 2002. (b) At 8:30 A.M., April 14, 2002, Notification 11 and Notification 12 are sent to all of this timer service's listeners. (c) The notification queue prior to 12:00 A.M., April 15, 2002.

graphics/07fig01.gif

The queue in Figure 7.1 contains three entries:

 1. (08:30am 04/14/2002, {Notification  11  , Notification  12  }) 2. (12:00am 04/15/2002, {Notification  21  }) 3. (05:00pm 04/17/2002, {Notification  n1  , Notification  n2  , Notification  n3  }) 

At 8:30 A.M. on April 14, 2002, Notification 11 and Notification 12 are sent to any listeners that have been added to this timer service instance. Notification 12 is a recurring notification with a period of five days, so it is added back to the queue in the entry (8:30am 04/19/2002, {Notification 12 }) . Now the timer service will wait until 12:00 A.M. on April 15, 2002, when it will send Notification 21 .

7.1.2 Timer Notifications

The notifications that the timer service sends are a subclass of the basic JMX Notification class:

 public class TimerNotification extends Notification {    // package private constructor; only the timer service may   // create instances   public Integer getNotificationID() { ... } } 

The value returned by the getNotificationID() method is the identifier associated with this notification when it was added to the notification queue.

Management applications commonly use this notification ID to control which notifications their notification listeners receive. Recall that when we add a NotificationListener instance to an MBean via the MBeanServer's addNotificationListener() method, our listener receives all notifications sent by that MBean unless we provide a NotificationFilter instance to indicate which ones we're really interested in. Listing 7.2 is a simple NotificationFilter implementation that filters TimerNotification instances according to their notification IDs.

Listing 7.2 A Notification ID “Based Instance of NotificationFilter
 import java.util.HashSet; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.timer.TimerNotification; public class TimerFilter implements NotificationFilter {   private final HashSet idset;   /**    * Create a new TimerFilter instance with no notification IDs enabled    */   public TimerFilter() {     this(new HashSet());   }   /**    * Create a new TimerFilter instance with the specified notification IDs    * enabled    * @param idset  the set of enabled notification IDs    */   public TimerFilter(Collection ids) {     this.idset = new HashSet(ids);   }   /**    * Determine whether or not the given notification is enabled    * @param notification  the notification in question    * @return true if notification is an enabled TimerNotification instance    */   public boolean isNotificationEnabled(Notification notification) {     if !(notification instanceof TimerNotification) {       return false;     }     return idset.contains(notification.getNotificationID());   }   /**    * Add a notification ID to the enabled set    * @param id  notification ID to enable    */   public void enableNotificationID(Integer id) {     idset.add(id);   }   /**    * Remove a notification ID from the enabled set    * @param id  notification ID to disable    */   public void disableNotificationID(Integer id) {     id.remove(id);   } } 

If a management application were interested in only notifications with IDs in the set {7, 11, 13}, it would create an instance of TimerFilter , enable those IDs, and then call addNotificationListener() with a listener and the TimerFilter instance it just configured:

 ...  TimerFilter tf = new TimerFilter(); tf.enableNotificationID(new Integer(7)); tf.enableNotificationID(new Integer(11)); tf.enableNotificationID(new Integer(13)); mbs.addNotificationListener(objname, listener, tf, new Object()); 

If the application loses interest in the notification with ID 11, it simply disables that notification via TimerFilter :

 ...  tf.disableNotificationID(new Integer(11)); 

Now invocations of handleNotification() will be limited to notifications 7 and 13.

7.1.3 The Timer Class

The Timer class implements the management interface defined by the TimerMBean interface. That interface is composed of a set of attributes that provide information about the notification queue controlled by the timer and a set of operations that allow you to start and stop the timer itself, add notifications to and remove notifications from the notification queue, and get information about a specific notification on the notification queue.

7.1.3.1 TimerMBean Attributes

The TimerMBean interface defines the five attributes listed in Table 7.1.

Table 7.1. TimerMBean Attributes

Attribute

Type

Description

AllNotificationIDs

Read-only

A Vector -valued attribute containing the notification ID for each notification currently on the notification queue

NbNotifications

Read-only

An int -valued attribute indicating the number of notifications currently on the notification queue

SendPastNotifications

Read/write

A boolean -valued attribute that indicates whether or not the timer should send notifications whose scheduled date and time have passed

Active

Read-only

A boolean -valued attribute that indicates whether or not the timer has been started

Empty

Read-only

A boolean -valued attribute that indicates whether or not the timer's notification queue contains any entries

7.1.3.2 Timer Notification Operations

The TimerMBean interface defines a suite of addNotification() and removeNotification() operations that management applications and MBeans use to schedule their notifications:

 public Integer addNotification(String type,                                 String message,                                Object userdata,                                Date date) public Integer addNotification(String type,                                String message,                                Object userdata,                                Date date,                                long period) public Integer addNotification(String type,                                String message,                                Object userdata,                                                                Date date,                                long period,                                long nbOccurences) 

All of the addNotification() operations construct a TimerNotification object, place it on the notification queue, and return an Integer ID for the notification rather than a reference to the notification itself. The only difference among the three versions is whether the new notification's period and number of occurrences are specified. Table 7.2 describes the notification's scheduling behavior in each possible case.

The timer service doesn't support scheduling notifications in the past; that is, the value of the date parameter can't be earlier than the current date and time. If it is, all of the addNotification() methods throw an IllegalArgumentException .

We can remove notifications en masse, or all notifications of a specified type, by calling removeAllNotifications() , or we can remove just the notification with a specific notification ID using removeNotification() :

 public void removeAllNotifications()  public void removeNotifications(String type) public void removeNotification(Integer id) 
Table 7.2. Timer Notification Scheduling Behaviors

period and nbOccurence Values

Scheduling Behavior

None

The notification is a one-shot notification. It will be sent once and not rescheduled.

period

The notification is a recurring notification. It will be sent at its scheduled date and time and then rescheduled to occur in period milliseconds. It will continue to be rescheduled until it is removed from the notification queue.

period and nbOccurence

The notification is a recurring notification. It will be sent at its scheduled date and time and then rescheduled to occur in period milliseconds. It will be rescheduled until it has occurred nbOccurence times.

Finally, the TimerMBean interface supplies methods that access the information about scheduled notifications:

 public Vector getNotificationIDs(String type)  public String getNotificationMessage(Integer id) public Object getNotificationUserData(Integer id) public Long getNbOccurences(Integer id) public Long getPeriod(Integer id) public Date getDate(Integer id) 

Use getNotificationIDs() to obtain a vector containing the notification IDs for all scheduled notifications of a specified type. Except for getPeriod() and getNbOccurences() (yes, occurrences is misspelled in the method name), each of the other five methods does just what its name implies: returns the value of the notification field indicated by its name . The getPeriod() method returns the specified notification's period unless the notification is a one-time occurrence, in which case getPeriod() returns null . The getNbOccurences() method returns the number of occurrences remaining on the specified notification's schedule; if the notification recurs indefinitely, a null value is returned.

7.1.3.3 Starting and Stopping

The final timer methods are responsible for controlling the service's execution:

 public void start()  public void stop() 

When start() is called, the Timer instance begins processing its notification queue and sending notifications at the appointed dates and times. Calling stop() halts the timer's processing of the notification queue. Of course nothing is ever that simple. What happens if a notification's appointed date and time come and go before the timer is started? It depends on the value of the SendPastNotifications attribute. SendPastNotifications is a boolean -valued attribute, so there are only two possibilities. Table 7.3 explains what happens in each.

Table 7.3. The Effect of SendPastNotifications on Timer Service Startup

SendPastNotifications Value

Timer Service Behavior

True

Any one-shot notifications whose scheduled times have passed are sent. Any recurring notifications are sent as many times as they should have occurred before the timer was started.

False

Any one-shot notifications whose scheduled times have passed are ignored. The notification schedules for any recurring notifications are updated, but no notifications are sent.

Setting SendPastNotifications to true will ensure that no scheduled notifications are "lost" as the result of a delay in starting the timer service. The downside is that a "notification storm" may occur when the timer service is started. In a notification storm , tens or hundreds of notifications arrive simultaneously and are dispatched to handlers, which then take some action in response. At the very least there will be a CPU spike as the notifications are dispatched and handled; the CPU spike may trigger other notifications, which will compound the problem, possibly snowballing into a system crash.



Java and JMX. Building Manageable Systems
Javaв„ў and JMX: Building Manageable Systems
ISBN: 0672324083
EAN: 2147483647
Year: 2000
Pages: 115

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net