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
@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
@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
/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()