Starting from EJB 2.1, Timer Services are available for building J2EE Applications that depends on time based services. Time based services are mostly used in scheduling applications. Technically, these scheduling applications are called workflows.
also read:
A workflow defines a configurable sequence of activities or tasks that will take place at a particular point of time. Before EJB 2.1, one has to manually code for building and deploying time-based workflow systems. But, with the invent of EJB 3.0, thanks to Annotations and Dependency injections, life has become still more easier for creating such applications.
What are EJB 3.0 Timer Services?
Consider a reporting Application, that will send report in the form of mails, every Monday, or a Billing Service that sends credit or debit bills on the 1st of every month. These applications depend on time-based events. To be more precise, these applications should allow developers to schedule some business logic or process so that they can be executed at some regular intervals of time. This is the core concept behind EJB Timers.
EJB Timer Services are services that are provided by the container (or the Application Server) and developers can take advantage of the timer services by registering one or more enterprise beans for time-based notification.
Different Types of Timers:
EJB basically supports two forms of Timer objects:
- Single Action Timer
- Interval Timer
a) Single Action Timer
A single action timer (or a single interval timer) is a one which will expire only once (as opposed to interval timer, where multiple expirations are possible).
Accordingly EJB supports two different ways for constructing a single interval timer.
i) One is to create the timer in such a way that it will expire at a particular point of time which is specified as a Date
ii) The other possible way is make the timer to expire after certain period of time (say after 10 hours or 1 day) which is usually specified in milliseconds. After the timer expires, the enterprise bean will receive a kind of notification, i.e the container will call the ejbTimeout() method (or the method that is annotated with @Timeout annotation).
b) Interval Timer
Interval timer (or multiple action timer), as its name suggests will recur (or happen) at multiple intervals of time. That is, these kinds of timer will have multiple expirations at regular intervals of time.
Two different ways of constructing the Timers are available:
i) The first approach is to create a timer to have an initial expiration at some point of time (which is usually specified as a Date) and to have the subsequent expirations happen at a specified interval.
ii) The second approach is to construct the timer whose initial expiration will happen after an elapsed duration of time (in milliseconds) and to have the subsequent expirations happen after a specific interval. For every expirations of the Timer object, the container continues to call the ejbTimeout() method (or the method that is annotated with @Timeout annotation) until the bean explicitly calls the cancel() method.
Timer Services API
The Timer Services API is small and has only 4 interfaces packaged with it. It is expected that more API related to Timer Services will be added in the future EJB specification. The interfaces are:
- TimerService
- Timer
- TimedObject
- TimerHandle
a) TimerService
This interface provides support for creating timers (single-action or interval) as well as retrieving the existing timers (that are created by one or more enterprise beans) from the container. Enterprise beans can use this interface for creating single-action or interval timer objects.
i) For creating timers
- Single-action Timers
The following two methods are available in the TimerService API for creating a single action timer:
- Timer createTimer(long duration, Serializable info)
- Timer createTimer(Date expiration, Serializable info)
Using the first method, a single action timer can be made to expire after a specified duration of time. The second method will be useful if the timer is needed to expire at a particular point of time. The second argument in both the versions will be useful, if application specific information has to be passed to the Timer objects, else it can be safely ignored by passing null.
- Interval Timers
Following are the ways to create an interval based timer object.
- Timer createTimer(long initialDuration, long intervalDuration, Serializable info)
- Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info)
Interval timers have options to specify the initial expiration in the form of milliseconds or as a Date object and the subsequent expirations can be expressed in milliseconds. In the first version, the initial expiration for the Timer object will happen after the initialDuration has elapsed and subsequent expirations will happen at the specified intervalDuration. The second version supports in specifying the initial time of expiration as a Date object and the rest of the information is the same as that of the first version. Similar to single action timers, these timers also allows the enterprise beans to pass application specific information.
ii) For iterating over the existing timers
Collection getTimers() – This method will return a collection of timers that were already created by other enterprise beans that may be in different parts of the system.
b) Time
This interface holds information about the timer objects that was previously created by enterprise beans.
- Serializable getInfo ()
Returns the application specific object that was passed previously by the enterprise beans while creating timer objects. The object must implement the Serializable interface.
- Date getNextTimeout()
Returns the time (as a Date object) that tells when the next expiration is going to happen for this timer object.
- long getTimeRemaining()
Returns the number of remaining milliseconds that is left before the next expiration happens for this timer.
- TimerHandle getHandle()
Returns an instance of TimerHandle object which at a later time can be used to reconstruct the Timer object.
- void cancel()
Cancels the timer object. After cancellation, enterprise beans that have already registered for getting time-based notification (through the ejbTimeout() method) will no longer receive events.
c) TimedObject
Enterprise beans can implement this interface to receive time-based notifications (or callbacks) on Timer objects. The ejbTimeout() method will be invoked by the container whenever the timer expires.
For a single action timer, the ejbTimeout() will be called only once, whereas for an interval timer, this callback method may be called multiple times.
void ejbTimeout(java.ejb.Timer timer)
This method is called by the EJB Container when the timer object has expired.
There are two possible ways for implementing a call back method:
- One way is to make the enterprise bean implement the TimedObject interface and to give an implementation for the ejbTimeout(Timer timer) method. For example,
@Stateless @Remote class MyBeanImpl implements MyBean, TimedObject{ Public void ejbTimedout(Timer timer){ . . } }
- The other way is to annotate a method that is defined within the enterprise bean class with the @Timeout annotation. In this case, there is no need for the enterprise bean to implement the TimedOut interface. The return type of this method must be void and it should accept only one argument of type Timer.
@Stateless @Remote class MyBeanImpl implements MyBean{ @Timeout public void myTimedOutMethod(Timer timer){ .... } }
d) TimerHandle
This interface is implemented by the container so that enterprise beans at a later point can use this handle to reconstruct the timer object. TimerHandle extends the Serializable interface. So, the clients may serialize the handle. Because of this, TimerHandle are local objects, hence it is illegal to pass this object as an argument to remote interfaces.
Timer getTimer()
Obtains a reference to the Timer object.
Timer Operations
The following summarizes the various timer operations that may happen once a timer object is created:
- Creation
- Cancellation
- Expiration
Creating Timer Objects
Timer objects are usually created by one or more enterprise beans. Only stateless session beans and message-driven beans can create timer objects. The reason why stateful session beans cannot create timer objects is not clear in the specification. So, as of now, creating timer objects within stateful session beans will result in IllegalStateException. However, it is expected that the future specifications may also mandate stateful session beans to support timers.
Here is the sequence of steps to be followed for creating a Timer object.
a) Get a reference to the EJBContext object (for session beans it is SessionContext and for message-driven beans, MessageDrivenContext is used).
b) Obtain a reference to the TimerService using the context object.
c) Create single action or multiple Timer objects using the TimerService object.
a) Getting a Reference to the Context object
With the new EJB 3.0 way, getting a reference to the Context object with the help of Annotation and Dependency Injection has become easy. Following is a sample code to get a reference to the SessionContext (in the case of session beans) and MessageDrivenContext (in the case of message driven beans).
@Resource Private SessionContext sessionCtx; @Resource Private MessageDrivenContext messageDrivenCtx;
When the container creates an instance of enterprise beans, it will process all the annotations that are listed and then perform a dependency injection. So, the result is that sessionCtx reference and the messageDrivenCtx will be populated with an instance of type SessionContext and MessageDrivenContext respectively.
b) Getting a Reference to TimerService:
Getting a reference to the TimerService object is relatively simple, just a call to Context.getTimerService() will do that, like this
TimerService timerService = sessionCtx.getTimerService(); TimerService timerService = messageDrivenCtx.getTimerService();
c) Creating Timer objects:
As discussed earlier, timers are of two kinds. Single-action and Interval timer, Depending on the requirement, create any of the two variations of the timer objects. Given below are some samples for creating different timer objects with different configurations.
i) A timer object that will expire after 10 seconds from now.
Calendar now = Calendar.getInstance(); Timer timer = timerService.createTimer(now.getTimeInMillis() + (10 * 1000), null);
ii) This timer object will expire on the 1st of March 2007.
Calendar firstMarch2007 = new GregorianCalendar(2007, Calendar.MARCH, 1); Timer timer = timerService.createTimer(firstMarch2007, null);
iii) Here, the timer object initially expires after 1 week of time and subsequent expirations will happen after two weeks of time.
long oneWeek = (7 * 24 * 60 * 60 * 1000); Timer timer = timerService.createTimer(oneWeek, (oneWeek * 2), null);
iv) Here, the timer has an initial expiration that happens on the 1st of March 2007 and subsequent expirations will happen after one week of time.
Calendar firstMarch2007 = new GregorianCalendar(2007, Calendar.MARCH, 1); long oneWeek = (7 * 24 * 60 * 60 * 1000); Timer timer = timerService.createTimer(firstMarch2007, oneWeek, null);
Canceling the Timer
Following are the three possible ways where a timer object can be made to cancel:
i) By explicitly calling the cancel method:
When the enterprise beans decides that they no longer want to receive any kind of notifications (via. ejbTimeout (Timer) method), then can call the cancel method in the Timer object. Upon invoking this method, the enterprise beans that have previously registered for getting notifications will no longer will receive callbacks(i.e the ejbTimeout() method wont be called anymore) from the container.
Timer timer = timerService.createTimer(…); . . . timer.cancel();
ii) When the timer object expires naturally:
Timer expiration is applicable only for single action timers (as interval timer will never expire, the only way to stop from further functioning is to explicitly call the cancel() method). Expiration for single action timers happen when the time (mentioned in the form of milliseconds) has elapsed, or the time (mentioned in the form of a Date object) duration is over.
Timer Expiration
Timer expirations can happen in any of the three cases:
- The given date (and time) has arrived.
- The period of time (that is given in the form of milliseconds) has elapsed.
- The recurring interval has expired (in the case of interval timer).
Persistence
Timers are persistent objects. To be precise, they are permanent objects. Whenever an enterprise bean creates an instance of a Timer object by using the TimerService, the TimerService will persist the Timer object by storing it in a database. Even if the server is abruptly terminated or it goes off, the timers will still be available and will become active once the server come backs to it normal state.
Timers and Transactions
Creating and canceling timers objects are made within a transactional context. So, if the transaction rolls back after creating a timer object, then the timer object creation is also rollbacked. Similarly, if the cancel method is called and the transaction is rolled back subsequently, the cancellation of the timer object is also rolled back.
Sample Implementation
Given below is a sample implementation that shows how an enterprise bean can use the facilities provided by the EJB Timer Services. Though, it is not a real time application, it may still provide the basic concepts that are back grounding the EJB Timer Services.
i) Scenario
This application is all about an employee who is giving status update to his manager at regular intervals. Though, the figures (startDate, endDate and the interval duration) and the status information may not mimic the real data, it may still provide a valuable way for writing a simple timer based application.
ii) Identified Objects
a) Worker:
Since Employee and Manager are really workers in a company, the purpose of this Worker class is to serve as a base class for the Employee and Manager class. It contains the common properties/attributes like name and id with its associated behavior.
b) Employee:
This class represents an employee object apart from inheriting the properties like name and id from its base class Worker, it contains a static method getStatusString() that randomly returns some status update message.
c) Manager:
Manager class that extends Worker class, apart from inheriting the common functionality, provides methods like reportStatus(Employee, status) that will accumulate the employee and his/her status information. It also has a printEmpStatusInfo() method, that will print all the status information of the employees for a particular duration of time.
d) StatusInfo:
StatusInfo is an information holder class that holds information about the employee and the manager objects and also the low-level information like the startDate, endDate, intervalDuration that will be used by the Bean for creating timer objects and publishing status information.
e) StatusUpdateBean:
The Local and the Remote Interfaces are represented by StatusUpdateLocal and StatusUpdateRemote respectively and the bean implementation is given by StatusUpdateBean. The remote interface has a method called setUpStatusInfo(StatusInfo) which is the only visible method as far as the client is concerned. Before invoking this method, the client (whether a stand-alone client, or a servlet ..), has to populate the StatusInfo object with relevant information like creating some test data representing the manager/employee objects, startDate/endDate/duration that represents when the employee has started giving status update to his manger, till what time he has to keep giving his updates, and the interval duration between the status updates.
f) Client:
The client gets a reference to the Remote interface through dependency injection (or through a JNDI lookup), populates the StatusInfo object with some test objects before calling the setUpStatusInfo(StatusInfo) method.
How it works
Once the setUpStatusInfo(StatusInfo) method is called, the Bean creates an instance of the Timer object using the TimerService factory interface which is obtained through the SessionContext object (via. Dependency Injection).
// Populates the SessionContext object using dependency injection. @Resource private SessionContext sessionContext; // Obtain a reference to the TimerService object TimerService timerService = sessionContext.getTimerService(); // Creates a timer object using the relevant information taken //from the StatusInfo object. // The following code creates a interval timer object with the //specified startDate and with the duration // as its interval. Calendar startDate = statusInfo.getStartDate(); long duration = statusInfo.getNextInterval(); Timer timer = timerService.createTimer(startDate.getTime(), duration, null);
Timedout Method
One can easily figure out that the updateStatus(Timer) is the timedout method for this enterprise bean as it is annotated with the @Timeout annotation. Within the method, the manager and the employee objects are obtained from the StatusInfo object and some dummy status is published to the manager object by calling the reportStatus(Employee, status) method. The manager objects keeps on storing the status against the employee object in a map. The method will be called infinitely if the timer object is not cancelled, since it is an interval timer. The timer is cancelled by checking whether the current time has crossed beyond the end time. If that’s the case, the timer object is cancelled and the status information for the employees is printed in the console.
Code snippet … @Timeout public void updateStatus(Timer timer){ Manager manager = statusInfo.getManager(); List employees = statusInfo.getEmployees(); for(int i=0; i System.out.println("Updating the Status Information.."); manager.reportStatus(employees.get(i), Employee.getStatusString()); } Calendar now = new GregorianCalendar(); if(now.after(statusInfo.getEndDate())){ manager.printEmpStatusInfo(); timer.cancel(); } }
Conclusion
Developers can take the advantage of the EJB Timer Services for building robust scheduling applications. One thing to remember is that, to be honest, developers are not encouraged to depend on Timer Services for building real-time applications (mission critical applications), as the expiration may not happen accurately at all times because of certain factors like the network latency, underlying implementation etc. Though, the timer services API is not exhaustive, it is believed that more and new functionalities will be added in the next specification of the EJB.
Frequently asked Questions on Timer Services
Q: a) What are Timer Services:
A: EJB Timer Services are container provided services for building scheduling (time-based) applications
Q: b) What are the two different types of Timers and how they are useful?
A: Timer comes in two forms. One is the single action timer and the other is interval timer. The former can be used in applications wherein which some logic has to be executed only once at a particular point of time (or after a specific duration) while the latter can be used to execute repeated logic at regular intervals.
Q: c) What is the use of @Timeout() annotation in EJB 3.0?
A: @Timeout() annotation when applied to a method will indicate that the method is a callback method for timer expirations and the container will call this method automatically whenever the timer object expires.
Q: d) How to pass application specific information to timer objects?
A: The createTimer() method (for both a single action and an interval timer) has an argument called info of type Serializable. This argument can be used to pass application specific information to timer objects (say, creditCardNumber and expiryDate in the case of Credit Card Processing System).
Q: e) What necessary steps are involved for creating a timer object?
A: Since timer services are container managed, we have to depend on the context object (EJBContext to be more specific) to make use of it. For a session bean, it is a SessionContext object and for a message driven bean, a MessageDrivenContext is used. Then, using the Context object, obtain a reference to the TimerService object. This TimerService factory object can then be used to create timers with different configurations.
Q: f) What different situations are there to make a timer object to expire?
A: A timer object can expire when the following conditions are met.
- When the enterprise bean, explicitly calls the cancel() method, (in this case, the ejbTimeout(Timer) callback method will never be called.
- When the duration that is mentioned during the creation of the timer object has expired, or the specified time (mentioned in the form of a Date object) has reached.
- The interval duration has elapsed in the case of an interval timer (in which case, multiple expirations may be possible)
.