How To use the Timer MBean

Author: Andreas Schaefer <andreas.schaefer@madplanet.com>

Introduction

As part of the JMX specification each JMX compliant server must provide a timer service to let the users being notified at a certain time, in a certain interval and/or number of occurrences. Therefore you can check for mails, check if some change on target (auto deployer) or notify the client for a date.

Preparation

  • First you have to add the timer service into the jboss.jcml therefore that the timer service is loaded, registered at the JMX server and the initialized and started (done by JBoss's Main.java class). This mbean tag looks like this:

      <mbean code="javax.management.timer.Timer" name="DefaultDomain:service=timer"/>
                   
    Keep in mind that there will be no notification about the startup. To check use the JMX HTML-Adaptor on port 8082 by default. The timer is loaded from the jmxri.jar file in /lib directory.

  • If you are not using JBoss then to the following (which means that you want to use a timer outside of JBoss (maybe on the client or administration side):

    1. Create a MBeanServer

         MBeanServer lServer = MBeanServerFactory.createMBeanServer();
                              

    2. Load and register the Timer MBean

         ObjectInstance lTimer = lServer.createMBean(
            "javax.management.timer.Timer",
            new ObjectName( "DefaultDomain", "service", "timer" )
         ); 
                              

    3. Initialize and start the timer service

         lServer.invoke(
            lTimer.getObjectName(), 
            "start", 
            new Object[] {},
            new String[] {}
         ); 
                              

  • Next step is to get the MBeanServer within your object to work with the timer.

    This is quite simple if your are in a MBean registered to the same JMX server because then you get it when you overwrite preRegister() method. When you are in the same JVM as the JMX server (in JBoss is any instance running within JBoss like EJBs or other classes). Then you can obtain the MBeanServer through:

       MBeanServer lServer =
          (MBeanServer) MBeanServerFactory.findMBeanServer( null ).get( 0 );
                

    For the rest it is a little bit more complicated. In a Java client you can use JBoss RMI connector which will be released as separat package till mid December 2000. Then you connect to a MBeanServer through the RemoteMBeanServer interface which is more or less the same.

  • We are nearly there: now we need the reference to the timer service to work on it (lServer can be either of type MBeanServer or RemoteMBeanServer):

     
       Set lBeans = lServer.queryMBeans(
          new ObjectName(
             "DefaultDomain", 
             "service", 
             "timer" 
          ),
          null
       );
       if( !lBeans.isEmpty() ) { // Should be the first and only element
          ObjectInstance lTimer = (ObjectInstance) lBeans.iterator().next(); 
                
  • Let's go to work with the timer. Because the timer sends a Notification Event to the listeners we have to register first:

     
       lServer.addNotificationListener(
          lTimer.getObjectName(), 
          new Listener(),
          // No filter
          null,
          // No object handback necessary
          null
       );
                
  • The Listener (in this case) is an inner class implementing the NotificationListener interface:

     
       public class Listener
          implements NotificationListener
       {
          public void handleNotification(
             Notification pNotification,
             Object pHandback 
          ) {
             // Here to whatever you want or call a method
             // in the outer class
             System.out.println( "You got a Notification: " + pNotification );
          }
       }
                
  • Finally we are ready to rock and roll. We set a timer event for a particular time and at this time the Listener.handleNotification() get called.

       Date lNext = new Date( new Date().getTime() + Timer.ONE_MINUTE );
       Integer lOneMinuteTimer = (Integer) lServer.invoke(
          lTimer.getObjectName(),
          "addNotification",
          new Object[] { 
             "IDoNotKnowWhatTypeIs",
             "I call you with this timer once",
             // No user object
             null,
             // I one minute from now
             lNext,
          },
          new String[] {
             "".getClass().getName(),
             "".getClass().getName(),
             "java.lang.Object",
             Date.class.getName()
          }
       );
                
  • A timer notification after an Hour from now repeating every minute for ten times.

       Date lNext = new Date( new Date().getTime() + Timer.ONE_HOUR );
       Integer lOneHourTimer = (Integer) lServer.invoke(
          lTimer.getObjectName(),
          "addNotification",
          new Object[] { 
             "IDoNotKnowWhatTypeIs", 
             "I call you with this timer once",
             // No user object
             null,
             // In one minute from now
             lNext,
             new Long( Timer.ONE_MINUTE ),
             new Long( 10 )
          },
          new String[] {
             "".getClass().getName(),
             "".getClass().getName(),
             "java.lang.Object",
             Date.class.getName(),
             Long.TYPE.getName(),
             Long.TYPE.getName()
          } 
       );
                
  • If you want to get rid of the second timer then do:

     
       lServer.invoke(
          lTimer.getObjectName(), 
          "removeNotification", 
          new Object[] {
             // You could also use the type: "IDoNotKnowWhatTypeIs"
             lOneHourTimer
          },
          new String[] {
             // If you remove by type: String.getClass().getName()
             Integer.TYPE.getName() 
          }
       );
                

Now the rest is quite simple. Have a look at the javax.management.timer.Timer class description and use the MBeanServer.invoke() method style.

Attention: When you have basic data type in the method signature then you have to use its wrapper class TYPE variable to get its class instead of using just "long" etc.

If anything is wrong or not correct please contact me at andreas.schaefer@madplanet.com. Also if you want to know more in detail or have a request for further infos.