Using Timers in J2EE Applications 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.
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.
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.
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 |
or
|
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.
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.
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: 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.
|
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:
Create the timer by invoking the EJB method: Invoke initializeTimer in the contextInitialized
method of a ServletContextListener of a web module.
Create a servlet and implement the init method to invoke the EJB method
that creates the timer. Set the load-on-startup property for the servlet to
automatically start the servlet when the web module is started.
Use a Startup class using the proprietary API of your J2EE container.
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>
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.
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.
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.
Timers are meant for long-running business processes; avoid using them with real-time events.
Avoid hard-coding expiration time and interval for your timer in your EJB, and accept them as user inputs or specify them as environment variables in deployment descriptors.
When creating multiple timers from the same bean, use a different info field
for each timer. Because all timer expirations (created by the same bean) invoke
the same ejbTimeout method, info is the differentiator. Otherwise, when
the bean receives a timeout call, it won't know which one of the timers
it created earlier has expired.
Provide the ability to cancel timers, which may be required during catastrophic events.
Choose what type of EJB you need for use with your timer. Stateless session beans are appropriate for most usages. Use the entity bean timer only when the timer is associated with the bean's identity.
Use the timer appropriately; avoid excessive use.
Use TimerHandle to persist and retrieve timer information.
Specify a transaction attribute for the ejbTimeOut method and business methods
that create/cancel timers.
RequiresNew is recommended for the ejbTimeOut method.
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.
Timers are part of the J2EE standard and the application will be portable across containers without depending on proprietary APIs.
Using the EJB Timer Service, which comes as a part of J2EE, has no additional cost. No extra configuration is required for an external job scheduler, and the developer need not be concerned about support for a favorite scheduler with the developer's preferred application server.
The timer is a container-managed service, and no separate thread pools/user threads are required, as with an external scheduler.
Transactions are fully supported with timers, unlike using an external job scheduler, for which extra setup may be required to support JTA.
By default, timers are persisted and survive EJB lifecycles and container crashes, and the support of persistence using a favorite job scheduler is not a concern. Timers, being part of the J2EE infrastructure, can be managed as objects, and J2EE vendors provide JMX MBeans for managing them.
Only J2EE 1.4 supports the EJB Timer Service, and not very many J2EE-1.4-compliant containers are available in production.
Most job schedulers provide APIs to schedule activity using standard Java classes; however, a timer API requires use of EJBs.
EJB timers lack support for cron-type timers, blackout dates, etc., which are available
with many job schedulers. Many J2EE-1.4-compliant containers, such as OC4J,
have added support for cron-based timers.
Many job schedulers support clustering and making the timer service highly available, but the J2EE specification does not mandate high availability or clustering for timers. Many vendors are coming up with implementations that will make timers highly available. Oracle plans to support clustering support for timers in a future production release of Oracle Application Server 10g.
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.
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.
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.