10
Timer Service

WHAT’S IN THIS CHAPTER?            

  • Advancements made in the timer service
  • Automatic timers
  • Programmatic timers
  • Setting the schedule with schedule expressions
  • Timers and transactions

WROX.COM CODE DOWNLOAD FOR THIS CHAPTER

The wrox.com code download for this chapter is found at www.wrox.com/go/projavaeedesignpatterns on the Download Code tab. The code is in the Chapter 10 download and individually named according to the names throughout the chapter.

Business applications need to perform tasks based on either calendar events or a timed schedule, whether it is to generate weekly user activity reports, repopulate a cache, or send a client a reminder e-mail. There are many use case scenarios. The timer service enables you to program timer events at specific times or regular intervals.

This chapter shows you how to configure the timer service using both automatic and programmatic techniques and how to schedule tasks using the cron-like schedule expressions.

WHAT IS THE TIMER SERVICE?

Can you imagine needing to wake up every morning to check the clock to see if it is time to get up? Probably not. Even before the invention of the alarm clock, people used sunlight or roosters to wake up. But roosters and the sun are not customizable. This lack of customization led to the invention of one of the most important devices of modern life: the alarm clock. Today even basic cell phones and fitness trackers offer alarms that you can adjust to different times and different days and even offer snooze options.

For a long time, neither Java SE nor Java EE offered a built-in solution for time-based operations. This lack of support was filled with community-led open source.

Traditionally, timer-based tasks would have been scheduled using a third-party tool such as Quartz,1 but such a tool tends to be tricky to use. Third-party tools require you to download and install a library, implement interfaces, and configure XML files. They’re anything but straightforward.

Fortunately for you and partly because of the difficulty faced by developers trying to use third-party libraries, a scheduling facility was introduced into the EJB 2.1 specification. This timer service satisfied the simplest use case scenarios. And for those complicated cases, there was still Quartz. Indeed, Quartz almost became the de facto standard of time-based operations in Java.

There is no default implementation for timers in Java SE. You can use Quartz in both Java SE and Java EE, but Quartz usage is a separate topic beyond this book. So this chapter skips the Java implementation and moves on to Java EE.

Advancements were made in the EJB 3.2 specification (the latest release) to the timer service. Introduced were the @Schedule and @Schedules annotations and cron-like calendar expressions. Now all but the most exceptional use case scenarios are satisfied. The timer service runs in the container as a service and registers Enterprise JavaBeans (EJB) for callbacks. It tracks the timers that exist and their schedules, and it even takes care of persisting the timer in case a server shuts down or crashes. The only thing the developer needs to do now is schedule the timer.

The timer service has been through a long development cycle. An overview of the advancements is summarized in Table 10.1.

Table 10.1 Timer Service Development

EJB AND JAVA VERSION DEVELOPMENT
EJB 2.1 Java 1.4 (November 2003) The ejbTimer implements the TimedObject interface.
The TimerService is accessed through the EJBContext method.
The business logic must be in the ejbTimeout method.
EJB 3.0 Java 5 (May 2006) The TimerService object is injected via direct injection using the annotation @Resource.
The business logic must be placed in a method annotated with @Timeout.
Schedule set by specifying a date, duration, or ScheduleExpression object or an XML configuration file.
Referred to as programmatic timers in Java EE 6.
EJB 3.1 Java 6 (December 2009) The container sets the TimerService object automatically; no injection is required.
The business logic must be placed in a method annotated with @Schedule or @Schedules.
The schedule is set in the annotations attributes and bycalendar-based EJB timer expressions.
EJB 3.2 Java 7 (June 2013) This extended the EJB Lite group to include the nonpersistent EJB timer service.
Includes enhancements to the TimerService API that allows access to all active timers in the EJB module.
Restrictions on Timer and TimerHandle that obliged references to be used only inside a bean have been removed.

IMPLEMENTING A TIMER IN JAVA EE

There are two types of timers in Java EE 7: automatic and programmatic. Automatic timers are set upon the deployment of an enterprise Java bean (EJB) that contains a method annotated with either @Schedule(...) or @Schedule(...). The annotated method is invoked by the container’s scheduler at the specified times, or time intervals defined within the arguments of the annotations. Such methods are referred to as callback methods. The timer starts ticking as soon as the EJB is deployed. A programmatic timer is set at run time by a method called from within the business logic. The time can be configured on the fly and invoked at anytime (or not at all). The timer start ticking when the programming logic determines that it should start.

Automatic Timers

The container invokes any method appropriately annotated with @Schedule and applies the schedule configuration specified in the annotation’s attributes. The attributes of the annotation are set following the calendar-based timer attributes in the “Timer Expression” section that follows. Here is a simple example:

@Schedule(second="*/1", minute="*", hour="*")
public void executeTask(){
    System.out.println("Task performed");
}

In this code snippet, the method executeTask is annotated @Schedule; this indicates to the container to set a timer upon deployment based on the time values specified in the annotations attributes. In this example the container invokes the executeTask method once every second.

By default, all timers are persisted and restored after a server shutdown or crash. If you set the optional attribute persistent to false, the timer is reset on server restart. You can set two additional attributes: info and timezone. If you set timezone, that time zone is respected when executing the timer; otherwise, the server time zone is used. The info attribute allows a developer to provide a description of the time that you can retrieve by calling the getInfo method of the Timer interface.

@Schedule(hour = "23", minute = "59", timezone = "CET",
          info = "Generates nightly report")
public void executeTask(){
    System.out.println("Task performed");
}

In the preceding code snippet, the executeTask method is invoked at 23:59 Central European time regardless of the time zone of the server on which it is deployed. A call to the method getInfo returns the text Generates nightly report.

You can configure more complex timers using @Schedules (note the pluralization) with multiple timer expressions.

@Schedules({
    @Schedule(dayOfMonth = "1"),
    @Schedule(dayOfWeek = "Mon,Tue,Wed,Thu,Fri", hour = "8")
})
public void executeTask() {
    System.out.println("Task performed");
}

This timer fires on the first of every month and every work day at 08:00. Listing 10-1 shows a complete example of an automatic timer.

One drawback of the automatic timer is that its schedule is set at deployment time and cannot be changed while the application is executing. Fortunately, there is a solution to this situation in the form of the programmatic timer, which you can set at any moment during run time.

Programmatic Timers

Programmatic timers are created at run time by invoking one of the create methods of the TimerService interface. Here is a simple example:

public void setTimer(){
    timerService.createTimer(30000, "New timer");
}

When the application code invokes the setTimer method, it creates a single-action timer that calls a “timeout” method in the same bean after the specified duration of 30,000 milliseconds. A “timeout” method is identified by the annotation @Timeout and must conform to certain requirements. It must not throw exceptions or return a value. It’s also exempt from needing to take a parameter, but if it does, it must be of type javax.ejb.Time. There can be only one “timeout” method.

@Timeout
public void performTask() {
    System.out.println("Simple Task performed");
}

The Context Dependency Injection (CDI) container injects a reference to the TimerService into an instance variable annotated @Resource. Here the container injects the instance variable timerService.

@Resource
TimerService timerService;

If you put together the previous three code snippets into a single bean and the application code calls the setTimer method, you create a timer that, after 30 seconds, calls the “timeout” method performTask. Listing 10-2 shows the simplest possible implementation of the programmatic timer in Java EE 7.

There are four timer creation methods in the TimerService interface with ten signatures. Table 10.2 shows an example of each one:

Table 10.2 Examples of the Four Timer Creation Methods

METHOD EXAMPLE
createIntervalTimer(new Date(), 10000, new TimerConfig()); This creates a timer that fires at the given date and then every ten seconds thereafter.
createSingleActionTimer(1000, new TimerConfig()); This creates a timer that fires after one second.
createTimer(30000, "Created new programmatic timer"); This creates a timer that fires after 30 seconds.
createCalendarTimer(new ScheduleExpression().second("*/10").minute("*").hour("*")); This creates a timer that fires every ten seconds.

All methods apart from the createCalendarTimer method can take as the first parameter either duration in milliseconds or a date. This sets up the point at which the timer is triggered. Here is an example:

SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy 'at' HH:mm");
Date date = formatter.parse("26/01/2015 at 17:56");
timerService.createSingleActionTimer(date, new TimerConfig());

In this code snippet, the “timeout” method is triggered at 17:56 on January 26, 2015.

If a scheduled timer is required, you can use the createCalendarTimer method. This method takes a ScheduleExpression object in which a schedule is set using the values described in the “Timer Expression” section that follows.

ScheduleExpression expression = new ScheduleExpression();
expression.second("*/10").minute("*").hour("*");
timerService.createCalendarTimer(expression);

In this code snippet, the schedule is set to trigger every ten seconds of every minute of every hour.

All the creation methods return a Timer object that represents the timer. This object has the method getHandle, which returns a serializable handle to the timer. The handle object can be persisted in a database or memory.

Later you can retrieve the handle object and return a reference to the timer by invoking the getTimer method. With this object in hand, you can retrieve useful information about the timer.

It’s easy to obtain information about the behavior of the timer. You can retrieve details regarding the timer’s schedule by calling the method getSchedule. This returns a ScheduleExpression object that has a getter method for each attribute. For example, getMinute() returns the value set for the minute attribute. The getNextTimeout method gets the point when the timer fires next, whereas the method getTimeRemaining returns the milliseconds before the timer expires.

The isCalendarTimer method returns true if the timer was set by constructing a ScheduleExpression object. You must call it before the getSchedule method to determine if the timer was set this way; otherwise, isCalendarTimer throws an IllegalStateException exception.

You can determine information about the timer’s persistent state by using the isPersistent method. Similarly, you can obtain information about the time by calling the getInfo method.

Timers are automatically cancelled when they expire. The container cancels the single-event timers, and you can cancel scheduled timers by calling the cancel method on the Timer object.

Timer Expression

Both programmatic and automatic timers can use calendar-based timer attributes. Table 10.3 shows the range of timer attributes that are used to set the timers. For automatic calendar-based timers, you set the calendar attributes in the annotation, whereas programmatic calendar-based timers use methods of the ScheduleExpression class to set the calendar attribute values.

Table 10.3 Calendar-Based Expressions

ATTRIBUTE DESCRIPTION PERMITTED VALUES
second One or more seconds within a minute 0 through 59
minute One or more minutes within an hour 0 through 59
hour One or more hours within a day 0 through 23
dayOfWeek One or more days within a week 0 through 7 (0 and 7 refer to Sunday)
Sun through Sat
dayOfMonth One or more days within a month 1 through 31
–7 through –1 (days from end of month)
Last
1st, 2nd, 3rd - nth
Sun through Sat
month One or more months within a year 1 through 12
Jan through Dec
year A particular calendar year 2014, 2015, etc.

It’s worth noting that the default value for the time attributes is 0 (zero) and for the non-numerical values it is * (asterisk).

This table has been appropriated from the Oracle’s Java EE 7 tutorial.2 The syntax is cron-like and should be familiar to most programmers. There are a few interesting characteristics worth pointing out.

The asterisk character is a placeholder for all possible values for the given attribute. For example, to set a schedule to trigger every hour, you would use the expression hour="*" for annotation-configured timers. For programmatic timers, you would invoke the method hour("*")on an instance of the ScheduleExpression class.

You can express values for each attribute as a list or a range. For example, the expression dayOfMonth="1, 15, last" sets the timer to trigger on the first, fifteenth, and last day of every month, whereas the expression hour="8-18" represents every hour from 08:00 until 18:00.

You can specify intervals and augment them with a starting point. The expression hour="8/1" triggers every hour starting from 08:00, whereas the expression hour="*/12" triggers every 12 hours. However, you can only set intervals for seconds, minutes, and hour attributes.

Table 10.4 offers a few examples of the calendar-based schedule in action.

Table 10.4 Examples of Expressions in Action

EXPRESSION ACTION
Second="10" Every ten seconds
hour = "2", Every two hours
minute = "15" Every 15 minutes
dayOfWeek="Mon, Fri" Every Monday and Friday at midnight
dayOfWeek="0-7", hour="8" Every day at 8 a.m.
dayOfMonth="-7" Five days before the end of every month at midnight
dayOfMonth="1st Mon", hour="22" First Monday of every month at 10 p.m.
Month="Mar", dayOfMonth="15" The 15th of the following March
year="2015", month="May" May 1, 2015 at midnight

New in the EJB 3.2 implementation is an enhancement to the timer service API that allows access to all active timers in the EJB module. These include both programmatically and automatically created timers.

In Listing 10-3, the bean is instantiated at start-up, and the manageTimer method is called. You retrieve a collection of all the active timers and iterate over the collection, printing out the timer info and the number of milliseconds that will elapse before the next scheduled timer expiration. Finally, you cancel the timer.

Transactions

Beans create timers within a transaction that the container manages. If this transaction is rolled back, so is the timer. If this transaction is rolled back then the timer is also rolled back. This means that its creation is rolled back and if it were canceled the cancellation would be undone and the timer reinstated. In listing 10-4 we show an example of a timer method marked with a transaction annotation.

Beans that use container-managed transactions set the transitions attribute on the method annotated @Timeout. Transactions are designated Required or RequiresNew. The transaction is started before the method is called. If the transaction is rolled back, the @Timeout method is called again.

SUMMARY

In this chapter, you have seen how to create automatic and programmatic timers and how they behave within a transaction. Timers can be quite useful when a cron-like job needs to run without disturbing the main business logic. You can see examples of timers in many projects and in almost all programming languages. The automatic timer is created by annotating a method with either @Schedule or @Schedules and hard-coding timer values as attributes of the annotations by declaring them in the ejb-jar.xml deployment descriptor. Programmatic timers are created by the application code and can change their values at run time.

The timer type you choose to solve your problem will depend largely on whether the frequency of the event will change based on business logic (client services) or technical requirements (repopulating a cache). The latter would best be served with a programmatic timer, whereas the former would benefit most from an automatic timer.

Timers are persisted by default to guard against server shutdowns and crashes and can be serialized in a database and later retrieved. Timers take part in a transaction and are fully rolled back with the transaction. It became a little easier to manage timers in EJB 3.2; you can retrieve all active timers in a collection and call timer methods on each instance.

With the new achievements on Java EE, timers became solid and capable, leaving most third-party frameworks obsolete.

  EXERCISES  

  1. Write a cache that repopulates a map from a database. Set the timer service to fire at 3 a.m., calling the repopulate method of the cache.

  2. Develop a programmatic timer that sends a notification to a client when his subscription is up for renewal.

NOTES

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset