ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

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:

  • TimedObject, which contains the callback method used to deliver timer-expiration notifications. The EJB bean implementation class must implement this interface.

  • The Timer interface, which contains information about a timer created through the EJB Timer Service.

  • TimerHandle, a Serializable handle used for persisting Timer information.

  • TimerService, which provides EJB components with access to the container-managed timer service and is exposed via the EJBContext interface.

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:

  • The bean class of our EJB must implement javax.ejb.TimedObject.

  • We have to create the timer by invoking the createTimer method, either in ejbCreate or in a business method of the EJB. If we choose to create the timer in ejbCreate or ejbPostCreate, the timer will be automatically initialized when a bean instance is created by a client. If we choose to create a business method, we have to expose this method in the EJB's remote/local interface. The clients will invoke this method to initialize the timer.

  • We must implement the ejbTimeOut method to perform the business logic when the timer is expired.

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.

Pages: 1, 2

Next Pagearrow