ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Using Timers in J2EE Applications Using Timers in J2EE Applications

by Debu Panda
10/13/2004

Job scheduling is nothing new--most enterprise applications require the scheduling of tasks and activities. For example, your application may need a timer service to run a business process once a day, or to clean up a temporary table when your application is initialized. UNIX's designers popularized job scheduling by making it simple with cron, and Oracle took this approach further by introducing database jobs and events with the Oracle database.

In this article, we will discuss how can you use a timer service in your J2EE 1.4 applications to schedule business task and activities.

What Is a Timer?

If you have been a Java developer for long, you know that your options were limited for building applications that required scheduling of tasks. J2SE 1.3 introduced application programming interfaces (APIs) to utilize timer services in Java applications, but support for it was missing in J2EE. If you wanted to use a timer service in J2EE, you had to either build a homegrown solution, use an open source implementation such as Quartz, or buy a commercial implementation, like Flux. If you want to know more about how to build timer applications using J2SE or Quartz, please refer to "Job Scheduling in Java," by Dejan Bosanac.

J2EE 1.4 introduced the concept of a timer service, which enables developers to create a program that can schedule a business process to occur at a predetermined time or at a regular interval. The EJB container manages the timer service to allow EJB methods to register to call back at a scheduled time or regular interval; EJB timers provide facilities like the Quartz job scheduler to schedule predetermined tasks and activities. Using a stateless bean as an example, I will demonstrate the steps required to create a timer to be used in a J2EE-1.4-compliant application server such as OracleAS Containers for J2EE (OC4J), the SunONE Application Server, or IBM WebSphere. We will also discuss the benefits and limitations of a timer service compared to commercial and open source job schedulers.

Using the Timer Service

The EJB container provides the timer service, which is the infrastructure for the registration and callbacks of timers and, hence, provides the methods for creating and canceling them.

Timer APIs

Following are the four interfaces in the javax.ejb package that an application employs for using the timer service in a J2EE application:

We must use the createTimer methods of the TimerService interface to create a timer. The timer can be a single-event timer, which can occur at a specific time or after a specific elapsed duration, or an interval timer, which may occur on a regular schedule. Essentially, three types of timers of possible, as outlined in the table below:

Type of Timer createTimer with Parameters
Single-event timer createTimer(long timeoutDuration, Serializable info)
Single event with expiration date createTimer(Date firstDate, Serializable info)
Interval timer with initial expiration

createTimer(Date firstDate, long timeoutInterval, Serializable info)

or

createTimer(long timeoutDuration, long timeoutInterval, Serializable info)

The timeoutDuration, or interval, is specified in milliseconds, and the initialExpiration is specified as a java.util.Date. The container will invoke the ejbTimeOut method of the EJB when the timeoutDuration is expired. If we decide to cancel the timer, we have to invoke the cancel method on the timer to do so prior to its expiration. Figure 1 depicts a overview diagram on how a Timer works in a typical J2EE container.

Timers and Types of EJBs

The use of timers is similar for all kinds of EJBs, with a few exceptions. A timer created for an entity bean is associated with its identity. However, the ejbTimeout method can be invoked on any pooled instance of a timer created for a stateless-session bean or a message-driven bean; the timer lifecycle is tied to the bean's lifecycle. Note that a timer cannot be used with stateful-session EJBs.

An Example EJB Using a Timer API

If we want to use the EJB Timer Service to schedule a business activity, we must take the following steps:

Figure 1 shows the relationship of the EJB and the timer service.

Figure 1
Figure 1: How a timer works

Let us assume that a business activity must occur at a regular interval. Therefore, we need to create an interval timer, and we will pass the initial expiration time and the interval as parameters.

Let us take a simple stateless-session bean that uses an EJB timer. In our example, TimerDemoBean has a method named initializeTimer that creates the interval timer, and a client to schedule a timer that occurs at regular intervals will invoke this method:

package TimerApp;
import java.util.Collection;
import java.util.Iterator;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.util.Date;
import javax.ejb.TimedObject;
import javax.ejb.TimerService;
import javax.ejb.Timer;
import javax.ejb.TimerHandle;
import java.rmi.RemoteException;

public class TimerDemoBean implements SessionBean,
                                      TimedObject

{
private SessionContext sc;
private TimerHandle timerHandle = null;

  public void ejbCreate()
  {
  }

  public void ejbActivate()
  {
  }

  public void ejbPassivate()
  {
  }

  public void ejbRemove()
  {
  }

  public void setSessionContext(SessionContext ctx)
  {
  sc = ctx;
  }

  public void initializeTimer(Date firstDate,
                              long timeout, 
                              String timerName)
  {
  try {
      // Create Your Timer
      TimerService ts = sc.getTimerService();
      Timer timer =
        ts.createTimer(firstDate, timeout, timername);
      System.out.println("Timer created at " +
             new Date(System.currentTimeMillis()) +
             " with a timeout: " + timeout +
             " and with info: " + timerName);

     // Store the TimerHandle, which is seriablizable 
     // and which can be used
     // to retrieve the timer values whenever required later.
      // Class-level attribute:
      timerHandle = timer.getHandle();
    } catch (Exception e) {

        System.out.println("Exception after create timer : "+
                                                 e.toString()); 

    }
    return; 

  }
   public void ejbTimeout(Timer timer)
  {
    //Implement Your Business Logic Here
    System.out.println("Performing My Task");

    System.out.println("ejbTimeout() called at: " + 
                        new Date(System.currentTimeMillis()) +
                        " with info:");

    return;
  }

  public void cancelTimer(String timerName)
  {
  try 
  {
    TimerService ts = sc.getTimerService();
    Collection timers = ts.getTimers();
    Iterator it = timers.iterator();
    while (it.hasNext())
    {
      Timer myTimer = (Timer) it.next();
      if ((myTimer.getInfo().equals(timerName))) {
           myTimer.cancel();
           System.out.println("Successfully Cancelled " +
                                                 timerName);

       }
    }
  }
  catch (Exception e) {

        System.out.println("Exception after cancelling timer : "+
                             e.toString());

    }
     return; 
  }

  public void getTimerInfo()
  {
    if (timerHandle != null) {
     Timer timer = timerHandle.getTimer();
     // Get Timer Infomation
     System.out.println(timer.getInfo());
    }

  }

}

We probably do not want to hard-code the initial expiration time and interval in our applications, and will instead pass parameters from the deployment descriptors or have users supply them according to their business requirements. Avoiding these steps makes the application portable and adds flexibility in the ability to to change the interval whenever you require. Unless it is an entity bean, I always avoid creating a timer in ejbCreate, because it does not provide a control to clients for when to create the timer. However, creating a timer in ejbCreate or ejbPostCreate makes sense for an entity bean for your application when a timer is associated with its primary key, such as in the case where you want to schedule a task to create an account for an employee when the employee is created.

The client code that will invoke the EJB method to create the timer will appear as follows:

Context context = getInitialContext();
TimerDemoHome timerDemoHome =
    (TimerDemoHome)PortableRemoteObject.narrow(
	    context.lookup("TimerDemo"), TimerDemoHome.class);
TimerDemo timerDemo;

// Use one of the create() methods below to create a new instance
 timerDemo = timerDemoHome.create();

// Call any of the Remote methods below to access the EJB
  timerDemo.initializeTimer( firstDate, timeoutInterval, 
                                             timerName );

You can find the example code that I've used in this article in the Resources section below.

When the application executes this code, this action will fetch the timer service and create an interval timer, and the container will invoke the ejbTimeout at the firstDate and at the specified intervals.

Automatically Scheduling a Timer

As we have seen from the previous example, the timer can be scheduled only by executing a business method from a client.

Some business applications require automatically scheduling a timer task. If your business application requires the automatic creation of a timer when your application is deployed, you have the following J2EE options:

I prefer to use a ServletContextListener because coding is simple and portable across J2EE containers. Here is an example how you can automatically schedule a timer when your application is deployed as follows:

public class MyLifeCycleEventExample 
    implements ServletContextListener
{
    ServletContext servletContext;

        /* Methods from the ServletContextListener */
    public void contextInitialized(ServletContextEvent sce)
    {
        servletContext = sce.getServletContext();
            try
    {
      Context context = new InitialContext();
      TimerDemoHome timerDemoHome =
          (TimerDemoHome)PortableRemoteObject.narrow(
              context.lookup("java:comp/env/TimerDemo"),
              TimerDemoHome.class);
      TimerDemo timerDemo;

      // Use one of the create() methods below to
      // create a new instance
      timerDemo = timerDemoHome.create();
      Date firstDate= new java.util.Date();
      
      // Call any of the Remote methods below to access
      // the EJB this code does not check whether the timer
      // has already been scheduled.
      // You should check this for duplicate timers
      timerDemo.initializeTimer( firstDate, 1800000, "MyTimer" );
      
      timerDemo.getTimerInfo();
      //Cancel Timer
      //timerDemo.cancelTimer("MyTimer");

    }
    catch(Throwable ex)
    {
      ex.printStackTrace();
    }
            
    }

    public void contextDestroyed(ServletContextEvent sce)
    {
    }

          protected void log(String msg)
    {
          System.out.println("[" + getClass().getName() +
                             "] " + msg);
    }
    
}

The only configuration required is to register the listener in the deployment descriptor of your web module (web.xml) as follows:

<listener>
   <listener-class>
      TimerWeb.MyLifeCycleEventExample
  </listener-class>
</listener>

Retrieving Timer Information and Canceling the Timer

The javax.ejb.Timer interface provides several methods to retrieve information about timers. For example, you can use the getInfo method to gather information about the timer and the getTimeRemaining method to find out the time remaining before expiration. It also provides a method--getHandle--that returns a TimerHandle, a serializable handle object that can be saved. We can retrieve the information about the timer by calling the getTimer method on the saved handle. If you are using timer with a CMP entity bean, you can use a container-managed persistence field to save the TimerHandle object.

In our sample code, the createTimer method demonstrates saving the handle into timerInfo, and the getTimerInfo method demonstrates the use of the TimerHandle to retrieve timer information.

For reasons beyond our control, the application may require the cancellation of timers, and, ideally, the program should enable this action. The cancelTimer method of our code demonstrates how to cancel a particular timer object based on its name.

Timer Persistence

Timers are persistent, and they survive container crashes and shutdown. Because they do so, ejbTimeout() is guaranteed to be invoked after container recovery. For interval timers, at least one invocation is guaranteed after recovery. Note that the ejbTimeout() invocation(s) after a container recovery are likely to not occur at the original intended time, and that the interval will not change after a recovery.

Timer and Transactions

Transactions are important for enterprise applications, and, for good reasons, timers are transactional. The creation and cancellation of a timer are done within the scope of a transaction and conform to ACID properties. If the transaction is rolled back, the creation or cancellation of the timer is undone.

We have to typically specify a transaction attribute for the ejbTimeOut method if we use a container-managed transaction demarcation. Only RequiresNew and NotSupported are allowed as transaction attributes for ejbTimeout. We can specify the transaction attribute of the ejbTimeout method as follows:

<container-transaction>
    <method>
        <ejb-name>EmployeeBean</ejb-name>
        <method-name>ejbTimeout</method-name>
    </method>
    <trans-attribute>RequiresNew</trans-attribute>
</container-transaction>

If we use RequiresNew as the transaction attribute for ejbTimeout, the container will start a new transaction prior to invoking this method. And if the transaction fails or is rolled back, the container will retry the ejbTimeout method at least once.

Timer Best Practices

Schedulers Versus Timers

Several job schedulers, such as Quartz and Flux, are available on the market, and it is difficult for developers to know when to use one. In this section, we will discuss the merits and demerits of timers compared to job schedulers.

Commercial schedulers provide many more features than the EJB Timer Service. It always makes sense to use a job scheduler if your applications need advanced features, such as a GUI admin tool to schedule tasks, workflow model for jobs, blackout window, etc. However, if you need an API to schedule activities in your J2EE applications, the EJB Timer Service is a perfect choice.

Merits of Timers

Limitations

Timer Service and Future Enhancements

While J2EE 5.0 is currently focussed at simplifying development, it is not very clear whether any enhancements are planned for Timer Service. It will be nice if support is added for cron expressions with timers. cron expressions are very powerful, simple to use, and many developers are familiar with them.

Here is an example of how a timer can be used with cron expressions with vendor-specific APIs. The example code uses a cross expression to create a timer that will fire at 8 a.m. on July 4 every year.

import oracle.ias.container.timer.EJBTimer;

import oracle.ias.container.timer.EJBTimerService;

...

String cronExpr = "0 8 4 7 * ";

EJBTimerService ets = (EJBTimerService) ctx.getTimerService();

EJBTimer et = ets.createTimer(cronExpr, info);

It will be useful for developers if J2EE 5.0 standardizes the use of cron expressions when creating a timer.

Conclusion

This article has presented the steps for using a timer in J2EE applications and has provided some guidelines. It has also examined merits and demerits of EJB Timer Service as compared to those of commercial job schedulers. You can start building your applications with a timer by using these guidelines with J2EE-1.4-compliant containers such as OC4J 10.0.3, the SunONE Application Server, etc.

Resources

Debu Panda is a Senior Principal Product Manager of the Oracle Application Server development team.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.