How to code EJB Timers like a pro

The EJB Timer Service can build applications that depend on time based services. In this tutorial we will show how you can receive timer notifications on your Session Beans.

In order to do that, an EJB needs to register with the Timer service and one of its methods will be called back on a time basis.

The callback can be called either at a specific time in the future (of after an elapsed time) or at regular intervals leading to this distinction:

  • Programmatic Timers using the @javax.ejb.Timeout annotation
  • Automatic Timers using the @javax.ejb.Schedule annotation

Let’s see both cases:

Programmatic timers using @Timeout annotation

If you need to execute an action at a specified time in the future, the simplest way to achieve it is by injecting the javax.ejb.TimerService in your application and using it to create a Timer. For example, in the following Singleton bean, we are creating a single action Timer as soon as the EJB deployed:
@Singleton
@Startup
public class UserRegistry {
        @Resource
        TimerService timerService;

        public ArrayList<String> listUsers;
        @PostConstruct
        public void init() {
                timerService.createSingleActionTimer(5000, new TimerConfig());
        }
        @Timeout
        public void createReports(javax.ejb.Timer timer){
           System.out.println("It is time to create a Report!");
        }
}

The @Timeout annotation lets you define which action to undertake when the timer fires. Running the above timer, will print the following log after 5.000 ms:

12:18:57,264 INFO  [stdout] (EJB default - 1) It is time to create a Report!

Another option to configure the Timer is via the ScheduleExpression which can schedule a Timer based on a Calendar. The expression represented by this object specifies when the callback will occur. For example, the following timer is scheduled to be executed on the 31th December 2014 at 23:59:59

ScheduleExpression scheduleExpression = new ScheduleExpression();
scheduleExpression.year(2014);
scheduleExpression.month(12);
scheduleExpression.dayOfMonth(31);
scheduleExpression.hour(23);
scheduleExpression.minute(59);
scheduleExpression.second(59);
timerService.createCalendarTimer(scheduleExpression, new TimerConfig());

Defining Automatic timers using the @Schedule annotation

If you want to schedule timed notifications at fixed intervals, then the simplest way to go is by using the @javax.ejb.Schedule annotation. This annotation uses a cron’s style to define a series of comma-delimited settings to express a time. Here is how to configure an event, which is repeated every hour:
@Schedule(second="0",minute = "0", hour = "*")
public void doHourlyJob() { . . }

You can even have multiple scheduling expressions to trigger your execution according to more than one rule as in the following example, which triggers an action at the end of the month and on the 15th day of the month:

@Schedules ({
    @Schedule(dayOfMonth="Last"),
    @Schedule(dayOfMonth="15", hour="12", minute="30")
})
public void doCleanUp() {
...
}

Here is a full example which combines both a @Schedule annotation to schedule Timer execution every minute and the @Timeout method to intercept it:

import java.util.ArrayList;
import java.util.Collection;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;

@Singleton
@Startup
public class UserRegistry {

  @Resource
  TimerService timerService;

  public ArrayList < String > listUsers;
  @PostConstruct
  public void init() {
    listUsers = new ArrayList < String > ();
    listUsers.add("administrator");

    timerService.createSingleActionTimer(5000, new TimerConfig());

  }
  public void addUser(String username) {
    listUsers.add(username);
  }
  public void removeUser(String username) {
    listUsers.remove(username);
  }

  public ArrayList < String > getListUsers() {
    return listUsers;
  }
  @Timeout
  public void createReports(javax.ejb.Timer timer) {
    System.out.println("It is time to create a Report!");
  }

  @Schedule(hour = "*", minute = "*", second = "*/60", info = "Every minute timer", persistent = false)
  public void printDate() {

    System.out.println("Schedule invoked at " + new java.util.Date().toString());

  }

}

Fetching the list of active Timers

The new EJB 3.2 API introduced a convenience method named getAllTimers that can be used to find all the active timers within the EJB module to which that bean belongs. Here is for example how to get details about a scheduled timer that is running every minute:

@Schedule(hour = "*", minute = "*", second = "*/60", info ="Every minute timer")
public void printDate() {
        Collection<Timer> timers = timerService.getAllTimers();
        for (Timer t : timers) {
                System.out.println(t.getInfo().toString());
        }
}

Persistent Timers

By default, all timers are persistent. That is, if the application server is shut down for some reason, the timer will become active again when the server is restarted. In the event that a timer expires while the server is down, the timer will expire and the @Timeout method will be called once the server is functioning normally again. To indicate that a timer should not be persistent, call TimerConfig.setPersistent(false) and pass it to a timer-creation method.

Another alternative is specifying the persistent=false attribute in the @Schedule annotation as in the following example:

@Schedule(hour = "*", minute = "*", second = "*/60", info ="Every minute timer",persistent=false)

If you need to manually delete a persistent Timer, once that you have stopped the application server you can move to the data folder, which is under your server’s configuration, and delete the timers that are persisted under the timer-service-data folder. See the following snapshot as an example:

$ tree standalone/
standalone/
├── configuration
├── data
│   ├── content
│   ├── timer-service-data
│   │   └── ee-ejb-server-timer.ee-ejb-server-timer.UserRegistry

How to manage your EJB Timers from the CLI

If you can perform standard management operations (cancel, suspend, activate, trigger) on the EJB Timers from the Command Line Interface. Simply connect to the CLI and refer to the deployment unit which contains the EJB TImer. Here’s an example which triggers the timeout method of a Timer in the application ejb-timer.jar:
/deployment=ejb-timer.jar/subsystem=ejb3/singleton-bean=SampleTimer/service=timer-service/timer=f74g373-jdy3-407b-jf83-h74gf63dd56g3:trigger()

Conversely, to cancel the above timer:

/deployment=ejb-timer.jar/subsystem=ejb3/singleton-bean=SampleTimer/service=timer-service/timer=f74g373-jdy3-407b-jf83-h74gf63dd56g3:cancel()

To suspend a Timer:

/deployment=ejb-timer.jar/subsystem=ejb3/singleton-bean=SampleTimer/service=timer-service/timer=f74g373-jdy3-407b-jf83-h74gf63dd56g3:suspend()

To activate the suspended Timer:

/deployment=ejb-timer.jar/subsystem=ejb3/singleton-bean=SampleTimer/service=timer-service/timer=f74g373-jdy3-407b-jf83-h74gf63dd56g3:activate()