Scheduling: the EJB 3 timer service

Scheduled tasks are a reality for most nontrivial applications. For example, your business application may have to run a daily report to determine inventory levels and automatically send out restocking requests. For most legacy applications, it is typical to have a batch job to clean up temporary tables at the start or end of each day. If fact, it is fair to say schedulers are an essential holdover from the mainframe days of batch computing. As a result, scheduling tools, utilities, and frameworks have been a development mainstay for a long time. The Unix cron utility is probably the most popular and well-loved scheduling utility. The System Task Scheduler, generally lesser known, is the Microsoft Windows counterpart of cron.

In the Java EE world, you have a few options for scheduling tasks and activities. Most Java EE application servers come with a scheduling utility that is sufficiently useful. There are also a number of feature-rich, full-scale scheduling packages available for enterprise applications. Flux is an excellent commercial scheduling package, while Quartz is a good-quality open source implementation. EJB timer services are the standard Java EE answer to scheduling. As you’ll soon learn, while it does not try to compete with full-scale scheduling products, the EJB 3 timer service is probably sufficient for most day-to-day application development requirements. Because it is so lightweight, the service is also extremely easy to use.


In the next few sections, we’ll build a scheduling service using EJB 3 timers and show you how to use the @Timeout annotation.

What are timers?

In a sense, the EJB 3 timer service is based on the idea of time-delayed callbacks. In other words, the service allows you to specify a method (appropriately called the timeout method) that is automatically invoked after a specified interval of time. The container invokes the timeout method on your behalf when the time interval you specify elapses. As you’ll see, you can use the timer service to register for callbacks triggered once at a specific time or at regular intervals.

We can only use timers in stateless session beans and MDBs because of their asynchronous, stateless nature. However, unlike stateless session beans and MDBs, timers are persistent and can survive a container crash or restart. Timers are also transactional, that is, a transaction failure in a timeout method rolls back the actions taken by the timer. Figure 5.5 illustrates how timers work.

How an EJB timer works. A client may invoke an EJB method which creates a timer that registers a callback in the EJB timer service. The EJB container invokes the timeout method in the bean instance when the timer expires.

Figure 5.5 How an EJB timer works. A client may invoke an EJB method which creates a timer that registers a callback in the EJB timer service. The EJB container invokes the timeout method in the bean instance when the timer expires.

As the figure demonstrates, an EJB method can register a time-driven callback with the container timer service. When the time interval specified by the EJB expires, the timer service invokes the timeout method pointed to by the EJB. We’ll show you how this works with a simple example next.

Using the timer service

Let’s explore the features of the EJB 3 timer service by adding a timer to the PlaceBid EJB we introduced in topic 2. We’ll add a timer in the addBid method to check the status of the newly placed bid every 15 minutes. Although we won’t code it, another compelling use case is to create a timer when an item is added for bidding. Such a timer could be triggered when the auction time expired and would determine the winning bidder. We’ll leave the implementation of this timer as an exercise for you.

Among other things, the timer we’ll implement will notify the bidder via e-mail if they have been outbid. We have omitted most of the code that is not absolutely necessary to explain timer functionality in listing 5.3. The complete code is included in the downloadable code samples if you are interested in exploring further.

Listing 5.3 Using the EJB 3 timer service

Listing 5.3 Using the EJB 3 timer service

We use EJB 3 resource injection to gain access to the timer service Q. In the addBid method, after we add the bid we schedule a timer service callback to occur every 15 minutes Q. The newly added Bid is attached as timer information when the timer is registered. At regular intervals, the monitorBid method is called by the timer service, which is designated with the @Timeout annotation Q. The monitorBid method retrieves the Bid instance attached as timer information and monitors the bid.

We’ll explore EJB timer services details using listing 5.3 as a jumping-off point in the next few sections, starting with ways to get access to the EJB 3 timer service.

Accessing the timer service

As you just saw in listing 5.3, the EJB timer service can be injected into a Java EE component using the @Resource annotation. Alternatively, you can get access to the container timer service through the EJB context:

tmp2F41_thumb

Let’s take a look at the complete definition of the TimerService interface to get a clearer picture of the range of options available (listing 5.4).

Listing 5.4 Specification for the TimerService interface is used to create either single-event or recurring timers

Listing 5.4 Specification for the TimerService interface is used to create either single-event or recurring timers

Listing 5.4 Specification for the TimerService interface is used to create either single-event or recurring timers

Which method you choose is largely a matter of taste. In general, if you are already injecting an EJB context, you should avoid injecting the timer service as well, in order to avoid redundant code. Instead, you should use the getTimer-Service method as in the previous code. However, if you aren’t using the EJB context for anything else, it makes perfect sense to simply inject the TimerService as we did in listing 5.3.

Next let’s take a closer look at the injected timer service.

Using the TimerService interface

In listing 5.3, we use the TimerService interface to register a Timer. As you’ll soon see, a Timer is simply a Java EE representation of a scheduled task. The createTimer method used in listing 5.3 is one of four overloaded methods provided in the TimerService interface to add Timers. The one we used specified that the Timer should initially trigger in 15*60*1000 milliseconds (15 minutes), repeat every 15*60*1000 milliseconds (15 minutes), and added a Bid instance as Timer information:

tmp2F4-4_thumb

The first version of the createTimer method O allows us to create a single-event timer that is fired only once and not repeated. The first parameter, duration, specifies the time in milliseconds, after which the timeout method should be invoked. The second parameter, info, allows us to attach an arbitrary piece of information to the timer. Note that timer info objects must always be Serializable, as is the Bid object we used in listing 5.3. Note also that the info parameter can be left null if it is not really needed.

You’ve already seen the second version of the createTimer method C in action in listing 5.3. It allows us to create recurring timers with initial timeout and interval durations set in milliseconds. The third version Q is similar to the first in that it allows us to create a timer that fires once and only once. However, this version allows us to specify the expiration value as a specific instant in time represented by a java.util.Date instead of a long time offset. The fourth Q and second versions of the createTimer method differ from each other in the same way. Using a concrete date instead of an offset from the current time generally makes sense for events that should be fired at a later time. However, this is largely a matter of taste. All of these methods return a generated Timer reference. In general, this returned value is not used very often. Behind the scenes, all of the TimerService methods associate the current EJB as the callback receiver for the generated Timers. The final method of the TimerService interface, getTimers ©. retrieves all of the active Timers associated with the current EJB. This method is rarely used, and we won’t discuss it further.

Having looked at the TimerService interface and how to create timers, let’s now take a closer look at how to implement timeout methods.

Implementing timeout methods

In listing 5.3, we mark monitorBid to be the timeout method using the @Time-out annotation:

tmp2F45_thumb

When the timer or timers created for the PlaceBid EJB expire, the container invokes the designated timeout method—monitorBid. Using the @Timeout annotation is by far the simplest, but not the only way to specify timeout methods. As you might have guessed, methods marked with the @Timeout annotation are expected to follow this convention:

tmp2F46_thumb

A bean can have at most one timeout method, which can be specified (through annotation @Timeout or deployment descriptor timeout-method) either on the bean class or on a superclass. If the bean class implements the javax.ejb.Timed-Object interface, the ejbTimeout method is the bean’s timeout method.

The Timer for which the callback was invoked is passed in as a parameter for the method as processing context. This is because multiple Timers, especially in the case of repeating intervals, may invoke the same timeout method. Also, as you saw in listing 5.3, it is often necessary to use the TimerService interface to pass around data to the timeout methods as Timer information.

We’ll finish our analysis of the EJB 3 timer service code by taking a closer look at the Timer interface next.

Using the Timer interface

As we mentioned, the container passes us back the Timer instance that triggered the timeout method. In the monitorBid method, we use the interface to retrieve the Bid instance stored as timer information through the getInfo method:

tmp2F47_thumb

A number of other useful methods are defined in the Timer interface. We’ll explore them through the definition of the Timer interface (listing 5.5).

Listing 5.5 The javax.ejb.Timer interface

Listing 5.5 The javax.ejb.Timer interfaceListing 5.5 The javax.ejb.Timer interface

The cancel method is particularly useful in canceling a timer prior to its expiration. You can use this method to stop timers prematurely. In our bid-monitoring example, we can use this method to stop the chain of recurring callbacks when bidding on the item is over.

It is vital to invoke the cancel method for recurring Timers when they are no longer needed. Otherwise, the EJB will spin in an infinite loop unnecessarily. This is a subtle, common, and easy mistake to make.

The getTimeRemaining method can be used on either a single-use or interval timer. The return value of this method indicates the remaining time for the timer to expire, in milliseconds. You might find that this method is rarely used. The getNextTimeout method indicates the next time a recurring Timer will time out, as a java.util.Date instead of a long time offset. Similar to the getTimeRemaining method, this method is useful in the rare instance that you might need to determine whether to cancel a Timer based on when it will fire next.

The getHandle method returns a Timer handle. javax.ejb.TimerHandle is a serialized object that you can store and then use to obtain information about the Timer (by using the getTimer method available through TimerHandle). This is a relatively obscure method that we’ll leave for you to explore on your own if you want to. You have already seen the getInfo method in action. This method is extremely useful in writing nontrivial timeout functions and accessing extra processing information attached to the Timer by the bean method creating the Timer.

Let’s now discuss situations where EJB Timers are an appropriate fit.

EJB timers and transactions

EJB Timers are transactional objects. If the transaction that a timer is triggered under rolls back for some reason (e.g., as a result of a runtime exception in the timeout method), the timer creation is undone. In addition, the timeout method can be executed in a transactional context. You can specify a transactional attribute for the timeout method—Required or RequiresNew—and the container will start a transaction before invoking the timeout method. If the transaction fails, the container will make sure the changes made by the failed method do not take effect and will retry the timeout method.

We’ll talk about EJB transactions in much greater detail in the next topic.

When to use EJB timers

Clearly, although EJB timers are relatively feature-rich, they are not intended to go toe-to-toe against full-fledged scheduling solutions like Flux or Quartz. However, under some circumstances they are sufficient if not ideal. Like almost all other technology choices, this decision comes down to weighing features against needs for your specific situation and environment.

Merits of timers

Here are some of the merits of using EJB 3 timers:

■ Timers are part of the EJB specification. Hence, applications using EJB timers will remain portable across containers instead of being locked into the nonstandard APIs ofjob schedulers like Quartz.

■ Since the EJB timer service comes as a standard part of a Java EE application server, using it incurs no additional cost in terms of time or money. No extra installation or configuration is required as would be the case for an external job scheduler, and you won’t need to worry about integration and support.

■ The timer is a container-managed service. No separate thread pools or user threads are required for it, as would be the case with an external scheduler. For the same reasons, the EJB timer service is likely to have better out-of-the-box performance than third-party products.

■ Transactions are fully supported with timers (see the sidebar titled "EJB timers and transactions"), unlike external job schedulers, in which you may need to do extra setup for supporting JTA.

■ By default, EJB timers are persisted and survive EJB lifecycles and container restarts. The same cannot be said of all third-party schedulers.

Limitations for timers

The following are the primary limitations of EJB timers:

■ EJB timers are meant for long-running business processes and not realtime applications where precision timing is absolutely critical. Commercial schedulers may provide much better guarantees in terms of precision than the EJB 3 timer service.

■ EJB timers lack support for extremely flexible cron-type timers, blackout dates, workflow modeling for jobs, and so on. These advanced features are commonly available with external job schedulers.

■ There is no robust GUI admin tool to create, manage, and monitor EJB 3 timers. Such tools are generally available for third-party job schedulers.

This concludes our analysis of EJB 3 timers and marks the end of this topic. In general, you should attempt to use EJB 3 timers first. Resort to third-party schedulers only if you run into serious limitations that cannot be easily overcome.

Although robust schedulers are a compelling idea, in general they are complex and should not be used frivolously. However, there are many complex, scheduling-intensive applications where robust schedulers are a must, especially in industries like banking and finance.

Summary

In this topic, we covered a few advanced concepts common to all EJB types:

■ The EJB object acts as a proxy between clients and container where you can use EJBContext to access container runtime information and services.

■ Interceptors are lightweight AOP features in EJB 3 for dealing with cross-cutting concerns such as logging and auditing. You can use interceptors at the EJB module level, class level, or method level.

■ EJB timers provide a lightweight scheduling service that you can use in your applications.

You’ll find these advanced features useful in moderate-sized, real-life applications.

The only two features common to session and MDBs that we did not cover in this topic are transaction and security management. You’ll learn more about these features in the next topic.

Next post:

Previous post: