Schedulers & Timers

EJBs have had support for programmatic timers since version 2.1. This was made possible by use of a combination of javax.ejb.TimerService interface along with the @Timeout annotation (which will be covered later). The @Schedule and @Schedules annotations were added in EJB 3.1. Let's look at how these annotations have made working with timers much more easier.

@Schedule

This annotation is used to designate a method as a target for a timed call back i.e. the EJB container invokes this method as per configuration/metadata provided in this annotation.

package ejbap.schedule;

import javax.ejb.Schedule;
import javax.ejb.Stateless;
import javax.ejb.Timer;

@Stateless
public class ScheduledReportingService {

    @Schedule
    public void generateAuditReport(){
        System.out.println("Generating audit report....");
    }

    /**
     * A Timer instance is injected 
     * automatically by the container
     */
    @Schedule
    public void generateSalesReport(Timer timer){
        System.out.println("Generating Sales report....");
        System.out.println("Next execution on - "+ timer.getNextTimeout());

    }
}

Please note that, in the above example, the @Schedule annotation is not configured with the schedule frequency. In such a scenario, the EJB container invokes (by default) the annotated method on a daily basis (at midnight)

@Schedule exposes a powerful cron-like syntax which provides a number of permutations and combinations are available as far the scheduling configurations are concerned. The syntax is so rich that it is not possible to enumerate all the possible combinations. Here are a few selective examples

package ejbap.schedule;

import javax.ejb.Schedule;
import javax.ejb.Stateless;

@Stateless
public class SchedulerConfigurationExamples {

    //Jan 1 (year on year)
    @Schedule(second="0", minute="0", hour="0", 
    dayOfMonth="1", month="Jan", dayOfWeek="*", 
    year="*")
    public void sendNewYearGreetings(){
        //logic
    }

    //every 10 minutes
    @Schedule(minute="*/10", hour="*")
    public void dbHealthCheck(){
        //logic
    }

    //every friday (midnight)
    @Schedule(dayOfWeek="Fri")
    public void timesheetReport(){
        //logic
    }
}

@Schedules

This annotation is to be used when you want to impose/declare multiple timers scheduling options to single method. All it does it accept multiple (an array) of @Schedule annotations

package ejbap.schedule;

import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.Stateless;

@Stateless
public class MultipleSchedules {

    @Schedules({
        //1 AM on Monday
        @Schedule(hour="1", dayOfWeek="Mon"),
        //2:30 AM on Friday
        @Schedule(hour="2", minute = "30", dayOfWeek="Fri")
    })
    public void generateAuditReport(){
        System.out.println("Generating audit report....");
    }

}

This is useful if you do not want to declare different methods for different timer configurations (although it's perfectly legal to do so)

Timer persistence

Timers are persistent by default i.e. their state is persisted in case the application terminates. One can toggle this using the persistent property in the @Schedule annotation

@Timeout

This annotation is useful when you want to adopt a programmatic way of working with timers rather than configuring them in declarative fashion using the annotations mentioned above. @Timeout is used a marker for the EJB container to be able to determine the trigger point which can be invoked when the timer expires. The method annotated with @Timeout contains the actual logic which you want to execute as part of your scheduled operation

If you compare this with @Schedule, the major difference you would notice is that @Timeout does not allow declarative configuration via annotation elements

package ejbap.schedule;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;

@Stateless
public class SimpleProgrammaticTimer {

    @Resource
    private TimerService ejbTimerSvc;

    public void trigger(Event event){
       TimerConfig configuration = new TimerConfig(event.detail, true);
       Timer timer = ejbTimerSvc.createSingleActionTimer(10000, configuration);
       System.out.println("Single action timer " + timer.toString() +" created");
    }

    @Timeout
    public void onTimeout(Timer timer){
        System.out.println("Event details: "+ timer.getInfo());

    }

    private static class Event {  
        private String detail;

        public Event(String detail) {
            this.detail = detail;
        }
    }
}

Since this annotation does not allow timer/scheduler configuration, it is used in conjunction with the javax.ejb.TimerService API which helps you create timers on the fly. It's helper method let you specify the timers in terms of duration, exact trigger date etc. as well as ad-hoc schedules (similar to what @Schedule offers) using the javax.ejb.ScheduleExpression class

package ejbap.schedule;

import javax.annotation.Resource;
import javax.ejb.ScheduleExpression;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

@Stateless
public class CalendarBasedProgrammaticTimer {

    @Resource
    private TimerService ejbTimerService;

    public void trigger() {
        ScheduleExpression schedule = new ScheduleExpression();
        schedule.dayOfMonth("1");//fist day of every month

        Timer timer = ejbTimerService.createCalendarTimer(schedule);
        System.out.println("Calendar based programmatic timer " 
                + timer.toString() + " created");
    }

    @Timeout
    public void onTimeout(Timer timer) {
        System.out.println("Timer schedule: " + timer.getSchedule());

    }
}

What's next ??

Next, we'll look at EJBs in their Web Service avatar !

Last updated