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

advertisement

AddThis Social Bookmark Button

Using Timers in J2EE Applications
Pages: 1, 2

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:

  • 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>

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

  • 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.

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

  • 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.

Limitations

  • 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.

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.