Chapter 7. Scheduling and timers

published book

This chapter covers

  • The basics of the EJB Timer Service
  • The basics of cron
  • Different types of timers
  • Declaring cron timers
  • Using ad hoc timers

So far in our study of EJBs, actions performed by beans must be initiated either on startup or as a result of an external action such as a method invocation from the web tier or to handle a message delivered via JMS. A user must click something in a web page or a JMS message must be delivered for an EJB method to be invoked and the application to do something. While most of the behavior in an application is prompted by user actions, there are times when you want the application to do something on its own either at a specific interval or at specific times. For example, you may want the application to send out an email reminder a day in advance, batch process records at night, or scan a legacy database looking for records to process every 15 minutes. To implement such behaviors you need the EJB Timer Service. Using the Timer Service, you can build Enterprise applications that schedule operations.

The EJB Timer Service underwent a major upgrade with the 3.1 release, which added support for cron-like scheduling. Prior to EJB 3.1, only delayed (performed in 10 minutes) and interval (executed every 20 minutes) operations were supported. If you were interested in scheduling operations for specific times or dates, you had to look outside the EJB specification to third-party solutions. Although these solutions were powerful, they added an extra layer of unnecessary complexity. Full cron-like scheduling is a core requirement for many applications, and support should be standardized and available in all containers.

In this chapter we’ll delve into how timers can be created both declaratively and programmatically. We’ll also examine how timers interact with transactions and EJB security. But first, let’s explore the basics of scheduling.

join today to enjoy all our content. all the time.
 

7.1. Scheduling basics

This chapter is concerned with scheduling method invocations on EJB using the EJB Timer Service. The concept of the Timer Service isn’t that different from the timer on your kitchen stove. When the timer goes off, you either pull the cookies out of the oven or stir another ingredient into the pot. Putting this in the context of the container, when a timer is created by an application—either from configuration files or programmatically—a timer is set. When the timer goes off, a bean is plucked from the method-ready pool (unless it’s a singleton bean), and the specified method is invoked, as shown in figure 7.1. In the case of a singleton bean, the existing singleton instance is used. The method is invoked just as if a user accessing it from a web interface invoked it. The container will perform dependency injection, and no special setup or logic is required on your part. If the timer is a reoccurring timer (every 10 minutes, for example), another timer is set to go off in 10 minutes.

Figure 7.1. Timer Service in a nutshell

In the upcoming sections we’ll define time-outs and look at cron functionality, the timer interface, and finally the different types of timers. This section has quite a bit of material for you to digest, but all we’re really covering is an egg timer on steroids. Let’s start by looking at the core features of the Timer Service.

7.1.1. Timer Service features

Let’s now turn our attention and examine the fundamental features of the EJB Timer Service. Using the EJB Timer Service, tasks can be scheduled at specific dates and times, for specific intervals, or after an elapsed duration. Although the Timer Service is robust and timers will survive server restarts/failures, the Timer Service doesn’t support real-time scheduling. This means that you shouldn’t use the EJB scheduling capabilities for situations where you must respond to real-world events within a measureable timeframe. A measurable timeframe is a period of time in which you absolutely must process a request or provide a response. The EJB Timer Service is applicable in situations that aren’t mission-critical (where something bad happens if you’re late by a nanosecond). For example, sending out an email broadcast at midnight with bid statuses is a good fit for the Timer Service. Using the Timer Service to monitor the pilot tubes on an airplane and calculate engine thrust would be a bad solution.

We’ll now examine the types of beans that support timers, fault tolerance, and methods for creating timers. After we’ve talked about these features in the abstract, we’ll dive into code.

Supported bean types

As of EJB 3.1, the EJB Timer Service can be used with stateless session beans, singleton beans, and message-driven beans. Stateful session beans aren’t supported—perhaps in a future revision support will be added, but it doesn’t exist today. What this means is that unless you’re using a singleton bean, it’s your responsibility to persist state between timer invocations. Each time a timer fires, a potentially different stateless session bean will be retrieved and invoked, as shown in figure 7.2. Singleton beans can be used where state needs to be maintained between timer invocations with one caveat: too many timers on a singleton bean can result in complications as timers clash attempting to execute on the same method at the same time or different methods at the same time. Let’s turn our attention toward fault tolerance.

Figure 7.2. Timer Service and the stateless pool
Fault tolerance

With any timer, the question of fault tolerance is an important one. Even the most basic alarm clocks include battery backup so that if the power is lost the clock continues to track time and remembers your wake-up time. Thus, you can sleep through the night, and an intermittent power failure—provided it doesn’t occur when the alarm is supposed to sound—won’t result in you being late for work or missing that important flight to Hawaii. If the power is out when the alarm is supposed to sound, there’s not much the alarm clock can do. With the EJB Timer Service, alarms will survive server restarts and failures with no additional effort on your part.

When a method is scheduled, the container creates a timer that will execute the specified method at the designated time. When the timer fires, the time condition has been met, and the method is either called in the case of a singleton bean or an instance is plucked from the method-ready pool and executed in the case of a stateless singleton bean. This is illustrated in figure 7.3. Note that singleton beans aren’t serialized between server restarts, so it’s important that beans persists their state. Timers aren’t supported with stateful beans.

Figure 7.3. Timers on stateless beans versus singleton beans
Timer creation

The scheduling of the execution can be done via configuration, programmatically, or by using annotations. Each approach fulfills a different need. Timers created via configuration are typically scheduled processes that execute on a fixed schedule. An example would be a nightly process for deleting temporary files or collecting performance data. Timers created programmatically are typically end user–driven and are an integral part of a business process. For example, an application might enable an administrator to send out an email broadcast at a specified date and time. This is an ad hoc task—not something an application should be redeployed for so that an updated configuration file can be reloaded. As you’ll see in this chapter, scheduling is fairly straightforward.

7.1.2. Time-outs

At first glance, a time-out might conjure images of being sent to the corner in grade school for an infraction. But EJB time-outs bear no relation to elementary school punishments. A time-out is simply an action, or method, that’s invoked when a timer fires. A timer firing is analogous to an alarm going off—you configure a timer and specify the time-out action. The action can be either an implementation of the ejbTimeout method defined in the javax.ejb.TimedObject interface or a method marked with the @Scheduled annotation. Time-outs can also be configured via XML configuration files. A time-out is associated with a timer. We’ll go deeper into timers and the implementation details of time-outs as we go through the rest of the chapter.

Note

A time-out is an action that’s performed when the timer operation completes.

7.1.3. Cron

Cron refers to a job scheduler available on many Unix systems including Mac OS X, Linux, and Solaris, among others. It launches applications or scripts at specific times to perform common tasks like rotating logs, restarting services, and so on. A configuration file, known as the crontab, specifies the commands to run along with the scheduling information. Cron is extremely flexible in its ability to schedule tasks. For example, using cron you could schedule a particular task to execute on the first Saturday of each month. With the release of EJB 3.1, the Timer Service gained scheduling capabilities comparable to cron; therefore, you might have seen articles or blogs extolling the new cron-like scheduling capabilities in EJB. Previously, scheduling wasn’t very robust and third-party solutions, such as Quartz, were used to fill in the gaps.

Figure 7.4 specifies the basic format of the crontab file. There are five setting positions that configure the scheduler followed by the command to execute. An asterisk signifies that all possible values are matched. For example, placing an asterisk in the first column matches every minute. This gives you considerable flexibility in configuring the execution of scripts. Although this isn’t as powerful as a batch-queuing system, it’s suitable for many everyday problems.

Figure 7.4. Format of the crontab file

If you aren’t familiar with cron, the following snippet will give you a taste. This is a cron file from the CentOS Linux distribution. In it, tasks that must run hourly, daily, weekly, or monthly are split up into separate files. The cron.hourly script will execute on the hour and so on:

20 * * * * root run-parts /etc/cron.hourly
25 1 * * * root run-parts /etc/cron.daily
50 3 * * 0 root run-parts /etc/cron.weekly
43 4 16 * * root run-parts /etc/cron.monthly

Both time-outs and cron are key to understanding the EJB Timer Service, which we’ll delve into next.

7.1.4. Timer interface

When you schedule a delayed invocation on a bean, you’re creating a timer. A timer knows when it’s going to go off and what method it’s going to invoke. Therefore, when you create timers, you provide the container with two pieces of information: a configuration setting defining when you want the timer to complete and a method, known as a time-out, to invoke when the timer completes. The container uses this information to create a timer. How the timer is implemented is up to the container provider—implementing timers robustly is obviously not trivial.

As you’ll see, there are three ways to configure timers: with annotations, programmatically, or via configuration files. Individual timers can be manipulated via the javax.ejb.Timer interface shown in listing 7.1. This interface provides you with one operation, cancel, and several methods for retrieving various pieces of information about the timer. To get a representation of a timer that can be serialized, use the getHandle() method. This method returns a javax.ejb.TimerHandle, which can be used to retrieve the timer instance. The TimerHandle is valid only within the container—it can’t be passed to remote code. Information on the timer, passed in when creating the timer, can be retrieved with the getInfo() method. This can be any serialized object but will be a string if you’re using the info attribute on the Schedule annotation. The getNextTimeout() will return a Date object with the time of the next time-out. Note that by the time you check it, the timer may have already fired. The getSchedule() returns a javax.ejb.ScheduleExpression with the scheduling information for cron-based timers. The getTimeRemaining() returns the number of milliseconds that will elapse before the timer fires again. The isCalendarTimer() returns true if this timer is a cron-based timer. Finally, the last method on the interface, isPersistent(), returns true if this timer will survive server restarts/failures.

Listing 7.1. Specification for the Timer interface
public interface Timer {
  void cancel();
  TimerHandle getHandle();
  Serializable getInfo();
  Date getNextTimeout();
  ScheduleExpression getSchedule();
  long getTimeRemaining();
  boolean isCalendarTimer();
  boolean isPersistent();
}

Timer instances are obtained from the javax.ejb.TimerService. The TimerService contains numerous methods for programmatically creating timers, as well as a method for retrieving all running timers. It’s important to note that the list of timers is transient—a timer retrieved from this interface may be invalid by the time you get around to inspecting it. Subsequent sections will cover the TimerService in more detail because it’s primarily used for creating timers programmatically.

Two topics we haven’t yet touched on are transactions and security with regard to timers. The topic of transactions is two-fold: how timer creations are impacted by transactions and how a time-out method participates within the context of a transaction. To answer the first question, see the following code snippet. If the call to the entityManager fails, the transaction will be marked for rollback, and this will result in the timer being cancelled provided that it hasn’t already executed. This also applies to timer cancellation: if a method that cancels a timer is subsequently rolled back, so is the request to cancel the timer.

public void addBid(Bid bid) {
  timerService.createTimer(15*60*1000,15*60*1000,bid);
  entityManager.persist(bid);
  ...
}

A time-out method is invoked within the context of a transaction. If the transaction is rolled back, the container retries the time-out. This happens in the case of a bean with container-managed transactions and with the time-out method marked with REQUIRED or REQUIRES_NEW.

With security, the time-out method is invoked with no security context. This means that if the getCallerPrincipal is invoked, it’ll return the container’s representation of an unauthenticated user. Thus, if the time-out method attempts to call any methods that have security requirements, the method invocation will fail. Remember that timers can be configured via configuration files and thus might have no connection with any user. Now that we’ve covered the basics of timers, it’s time to look at the different types of timers.

7.1.5. Types of timers

There are two types of timers for EJBs: time-delayed timers and calendar-based timers. The time-delayed timers were added in EJB 2.1 and can be thought of as sophisticated egg timers. You can specify that you want a method to execute at regular intervals, at a specific point in time, once after an elapsed time, and so on. For example, time-delayed timers could be used to refresh cached pick lists in a singleton bean every 20 minutes. These timers are useful but not as flexible or as powerful as the calendar-based timers.

Calendar-based timers are based on the cron scheduling concepts we covered earlier. With calendar-based timers, complex execution schedules can be constructed. Cron-based scheduling is very powerful and simplifies support for a wide variety of temporal business progresses. For example, a data synchronization process can be scheduled to start during the middle of the night and pause before people arrive in the morning so as to not negatively affect system performance during the workday.

Looking at timers based on whether they’re time-delayed or calendar-/cron-based is one approach to understanding the Timer Service. This approach enables you to compare the services available prior to EJB 3.1 and afterward. If you’re working with an existing EJB 3 system, this puts using external libraries such as Quartz into perspective.

Another approach to decomposing the functionality available with the Timer Service is to break down timers by how they’re created. Timers can be created either declaratively or programmatically. Declarative timers are built into the application and can be changed only via configuration, which requires an application restart. Programmatic timers can be created at runtime to implement time-based business processes. Let’s start by looking at declarative timers.

Get EJB 3 in Action, Second Edition
add to cart

7.2. Declarative timers

Either placing annotations on bean methods or declaring them in an application configuration file creates declarative timers. Timers created programmatically are best used for routine maintenance tasks or business processes that really don’t change. For example, declarative timers are a good fit for recalculating performance of a portfolio every night, or, in the case of ActionBazaar, downloading the latest UPS tracking information to know what shipments have been received. Because timer configuration files are container-specific, we’ll focus this section on the @Schedule annotation. This annotation was added with EJB 3.1 and configures calendar-/cron-based timers. To create time-delayed timers, you need to use the programmatic API discussed in section 7.3.

7.2.1. @Schedule annotation

Placing the @Schedule annotation on the method to be used as the time-out creates a declarative timer. The annotation can only be used in singleton beans, stateless session beans, and message-driven beans. The following code shows the definition of the annotation. If no attributes are specified, the timer will fire at midnight every day. The info attribute can be used to provide descriptive text that can be retrieved at runtime—it has no effect on the execution of the timer:

@Target(value=METHOD)
@Retention(value=RUNTIME)
public @interface Schedule {
  String dayOfMonth() default "*";
  String dayOfWeek() default "*";
  String hour() default "0";
  String info() default "";
  String minute() default "0";
  String month() default "*";
  boolean persistent() default true;
  String second() default "0";
  String timezone() default "";
  String year() default "*";
}

The method on which the @Schedule annotation can be placed has the same requirements as the @Timeout annotation. The method can’t return a value and arguments are limited to the javax.ejb.Timer object discussed earlier. Thus, the following time-outs are legal method prototypes:

void <METHOD>()
void <METHOD>(Timer timer)

With declarative cron timers, multiple timers can be registered for a single method. This is accomplished via the @Schedules annotation. This annotation takes an array of @Schedule annotations. Remember that a timer isn’t associated with a specific instance so it doesn’t matter if two or more timers are registered for the same method—both fire at the same time and each will operate on a completely different instance. When a timer fires, a new instance will be pulled from the pool; there isn’t a one-to-one correspondence between a timer and a bean.

7.2.2. @Schedules annotation

The @Schedules annotation is used to create multiple calendar-based timers on a single time-out method. It only accepts an array of @Schedule annotations. It’s straightforward to use:

@Target({METHOD})
@Retention(RUNTIME)
public @interface Schedules {
  javax.ejb.Schedule[] value();
}

Before we look at an example, let’s backtrack and look at the parameters of the @Schedule annotation.

7.2.3. @Schedule configuration parameters

A cron timer is specified using a calendar expression that’s very similar to the format used by the cron utility. The calendar expression comprises seven attributes: second, minute, hour, dayOfMonth, month, dayOfWeek, and year. For each of these attributes, there’s a well-defined set of values and syntax rules for building expressions that include specific ranges, lists, and increments. Table 7.1 summarizes the attributes along with the default values for each.

Table 7.1. EJB cron scheduling attributes

Attribute

Allowable values

Default

second [0,59] 0
minute [0,59] 0
hour [0,23] 0
dayOfMonth [1,31] *
month [1,12] or {“Jan,” “Feb,” “Mar,” “Apr,” “May,” “Jun,” “Jul,” “Aug,” “Oct,” “Nov,” “Dec”} *
dayOfWeek [0,6] or {“Sun,” “Mon,” “Tue,” “Wed,” “Thu,” “Fri,” “Sat”} *
year A four-digit calendar year *

It should be noted that by default timers operate within the time zone where the server is running. To specify a different time zone, you’d use the timezone attribute and specify a value from the IANA Time Zone Database. The valid values are specified in the Zone Name column. You can also query the java.util.TimeZone class to find the string representation. To put this in perspective, let’s put declarative timers to use in ActionBazaar.

7.2.4. Declarative timer example

Let’s explore the features of the declarative cron timer by using it to send out monthly and holiday newsletters. The monthly newsletter highlights items that attracted heavy bidding along with similar items and profiles of select sellers. In addition, a holiday newsletter will be broadcast to coincide with major holidays and special events such as Black Friday. Both tasks will make use of declarative cron timers.

To implement this feature, you’ll add a new stateless session bean, Newsletter, to ActionBazaar. The method skeleton is shown in listing 7.2. The Newsletter class will use container-managed persistence. Because requesting the list of users is restricted to administrative users, the Newsletter bean will run as an administrator so that a security violation exception isn’t thrown. Remember that timer methods execute as the nonauthenticated user.

One important use case to consider is what happens in the event of a container crash while the Newsletter bean is in the process of sending out newsletters. The container will attempt to reexecute the method when the container is restarted. Emailing a large distribution list will take a long time and the email service isn’t transactional. To get around this limitation, you can use JMS. As the service iterates over the users to be emailed, a new JMS message is inserted into the queue. If for any reason the method fails, no emails are sent and the transaction is rolled back. Additionally, with JMS beans sending out the actual emails, the email load can be load-balanced with multiple message-driven bean instances processing email requests. The code for this advanced behavior isn’t shown in the following listing but is available online. This demonstrates how the various aspects of EJB thus covered can be used to build a robust service.

Listing 7.2. Scheduling newsletters and reminders

In this listing, the NewsletterBean class is first declared as running as an administrator. This enables the bean to retrieve the list of users that’s restricted for security reasons. Next, the sendMonthlyNewsletter method is annotated with a schedule annotation specifying that the newsletter should be sent out on the first of each month. The sendHolidayNewsletter uses the @Schedules annotation to configure a broadcast for Thanksgiving and Christmas.

Now that you have a basic grasp of declarative timers, let’s dig into the syntax to see what’s truly possible. The example in listing 7.2 only scratches the surface.

7.2.5. Cron syntax rules

The syntax rules for calendar-based scheduling are straightforward. Table 7.1 documents the attributes along with the valid values and the default values. But that table isn’t the complete story. You may have noticed that the second, minute, and hour attributes on the @Schedule annotation are typed as strings and not integers. This is because you can provide expressions to attributes for constructing complex schedules. For example, you could create a timer that executes only Monday through Friday or a timer that executes every other week. If you were limited to single values or the scheduling capabilities prior to EJB 3.1, you wouldn’t be able to easily implement this functionality. The attributes support the following syntax forms: single value, wildcard, list, ranges, and increments.

Single value

Single values are the most straightforward and easiest to understand. Table 7.1 lists the valid values that can be used for each attribute. The values are case-insensitive. For some attributes, there are two representations—either numeric or text—as in the case of days of the week where Monday can be represented as either "Mon" or "0". The following are some examples of setting an attribute to a single value:

@Schedule(second="0", minute="1", hour="23", dayOfMonth="1", month="Apr", dayOfWeek="Mon", year="2015")

In this example, a timer is created that will execute on at 11:01:00 on the first day of April and the first Monday of April if the year is 2015. This expression is somewhat deceiving because the dayOfMonth and dayOfWeek are combined using an or, whereas the other attributes are combined using a logical and. Thus, this expression will fire on April 1, 2015, and April 6, 2015.

Wildcard

The wildcard * matches all possible values for a given attribute. If you’ve used either ls on Unix or dir on Windows, this should be familiar. The wildcard is used in situations where you want the expression for an attribute to match all possible values but you don’t want to list all of the values. The wildcard can be used on all attributes but in most circumstances it’s not advisable to use it on second and minute. Running a task every second or every minute will have an adverse impact on system performance. Frequent polling in an Enterprise application reduces scalability and responsiveness. Let’s look at an example using the wildcard:

@Schedule(second="*", minute="*", hour="*", dayOfMonth="*", month="*", dayOfWeek="*", year="*")

In this example, the timer will fire on every second of every minute, of every day, of every month, of every year. This example isn’t terribly useful but shows that each attribute supports the wildcard.

List

The list expression is composed of single values separated by a comma. The list can contain duplicate entries but they’re simply ignored. Whitespace between commas and the values are also ignored. A list can’t contain a wildcard, sublists, or increments. But a list can contain a range; for instance, you could specify Monday through Tuesday and Thursday through Friday. The following is an example:

@Schedule(second="0,29", minute="0,14,29,59", hour="0,5,11,17", dayOfMonth="1,15-31",year="2011,2012,2013")

This timer will execute for the years 2011, 2012, and 2013 on the first and for days 15–31, every 6 hours, every 15 minutes of those hours, and every 30 seconds. The timer will thus fire on 0:0:0 1, 2011, as well as 0:0:29 1, 2011, and so on. Note that dayOfWeek was omitted to simplify the already complex example.

Range

You’ve already seen examples of ranges in the example on lists. A range enables you to specify an inclusive set of values. A single value is separated by a dash (-), where the value preceding the dash is the start value and the value after the dash is the end value. A range may not contain the wildcard, lists, or increments. Here’s a simple example using ranges:

@Schedule(hour="0-11",dayOfMonth="15-31",dayOfWeek="Mon-Fri",month="11-12", year="2010-2020")

In this example the timer is going to execute for years 2011–2020, for the months of November and December, for days Monday through Friday of the last half of the month, and from midnight until noon. Ranges can also be used for the minutes, seconds, and dayOfWeek attributes, but this would have made this example too complex.

Increments

Increment support enables the creation of timers that execute at fixed intervals. It’s composed of a forward slash, where the value preceding the slash specifies the starting point and the value after the slash specifies the interval. Increments can be used only with second, minute, and hour attributes. The increment executes until it hits the next unit—if the increment is set on the second, the increment will terminate once the next minute is reached. Ditto for minute and hour. Wildcards may be used when specifying the starting position but not following the slash. Let’s look at a simple example:

@Schedule(second="30/10", minute="*/20", hour="*/6")

In this example, the timer will fire every 10 seconds, after a delay of 30 seconds, every 20 minutes, within every sixth hour. Thus, starting the timer at midnight would result in it firing at 06:20:40, 6:40:30, 12:20:40, 12:40:30, and so on. None of the other attributes were specified, because they don’t support increments.

Sign in for more free preview time

7.3. Using programmatic timers

In the previous section you were introduced to declarative timers using the @Schedule and @Schedules annotations. Declarative timers are useful when the task to be scheduled and its scheduling parameters are known. Declarative cron timers are useful for tasks such as log rotation, batch processing of records off-hours, and other well-known schedulable business processes. Ad hoc timers, on the other hand, aren’t known in advance and are created dynamically at runtime as required. Using the ActionBazaar newsletter example, hardcoding holiday newsletter broadcasts into the application isn’t flexible. Because ActionBazaar is used in different countries, additional holiday broadcasts will be required. Obviously recompiling the application for additional holidays would be excessive. A superior approach is to use ad hoc timers and let a marketing administrator schedule newsletter broadcasts at runtime.

Ad hoc timers are thus created programmatically at runtime. Functionally they’re every bit as powerful as the declarative timers. The only difference is that ad hoc timers are created programmatically at runtime and each bean is limited to one time-out because only one method can be annotated with @Timeout. As you’ll see, there’s a variety of different methods to choose from when creating a programmatic timer.

7.3.1. Understanding programmatic timers

Ad hoc timers are created via the javax.ejb.TimerService. The TimerService can either be injected via the @Resource annotation or acquired from the javax.ejb .SessionContext. Once acquired, TimerService has numerous createTimer variations that simplify timer creation. Two types of timers can be created with the TimerService: interval timers and calendar timers. Calendar timers are also known as cron-based timers and were covered earlier. Interval timers made their appearance in EJB 2.1 and are also supported.

Listing 7.3 contains the TimerService interface. With the exception of the getTimers() method, all other methods are responsible for creating timers. Each method returns a javax.ejb.Timer object. The Timer object can be used for retrieving basic information about the timer, such as whether it’s persistent, the time remaining until it fires, and a method for cancelling the timer. The getHandle() method returns a javax.ejb.TimerHandle, which supports serialization. The javax.ejb.Timer object can’t be serialized and thus shouldn’t be stored in a member variable of a stateful session bean, JPA entity, and so on. The javax.ejb.TimerHandle provides a method enabling the current Timer instance to be returned.

Listing 7.3. TimerService interface

The methods for creating a calendar-based timer accept a javax.ejb.Schedule-Expression and optionally a javax.ejb.TimerConfig object. The ScheduleExpression specifies when the timer should fire and has methods for configuring dates, times, and so on. The second block of methods creates the interval-based timers, which are timers that execute after a fixed period of time and possibly repeatedly. The third block creates single-action timers, which are timers that fire only once after a specified time period. Many of the methods optionally accept an info object that can be null if you don’t wish to use it. The only requirement on the object passed in is that it must implement the java.io.Serializable interface; otherwise everything else is up to you. The info object is a container for you to pass information to the timer when it executes—whatever information you choose.

Not mentioned in the discussion is the getTimers() method, which returns a collection of all outstanding timers. You can iterate over this list, cancel outstanding timers, and find out when the next timer will execute. One thing to keep in mind is that the timers may execute by the time you retrieve them from the TimerService—be careful not to introduce race conditions by depending on your ability to reach in and cancel timers before they execute.

Listing 7.3 referenced two additional classes: javax.ejb.ScheduleExpression and javax.ejb.TimerConfig. The ScheduleExpression class is used to specify when the timer should fire. It has a no-argument constructor and methods for setting the day of the week, month, year, hour, second, and so on. Each method returns the same ScheduleExpression instance enabling chaining so that the schedule can be defined on a single line. The TimerConfig object is a container for additional timer configuration information. It encapsulates the info object to be passed back to a time-out method along with a flag indicating whether the timer is persistent and thus should survive server restarts.

When scheduling using the TimerService, the bean invoking the schedule methods must have a time-out method. When using the TimerService, you’re specifying an alarm for the current bean into which the TimerService was injected—you can’t specify another bean. The bean must either have a method annotated with @TimeOut or implement the TimedObject interface. This will be demonstrated in the ad hoc timer example.

The TimerService participates in transactions. When a new timer is created within the context of a transaction, the timer is cancelled if the transaction is rolled back. The time-out method can be executed within the context of a transaction. If the transaction fails, the container will make sure the changes made by the failed method don’t take effect and will retry the time-out method. Now that you have a basic handle on ad hoc timers, let’s take a look at an example from ActionBazaar.

7.3.2. Programmatic timer example

Marketing frequently has the need to send out flyers advertising items for sale on ActionBazaar and enticing potential bidders and sellers to check out the site. Timing is critical for the flyer. Send it out toward the end of the workday and people will probably forget about the notice by the time they get home. Send it out before a long holiday weekend and it’ll stay buried in people’s inboxes. As a result, when the flyer is approved and ready to be sent isn’t necessarily the time that it should be sent. When uploading a flyer for distribution, ActionBazaar prompts for the date and time the email blast should be sent. This is similar to the previous newsletter example except that it’s an ad hoc email blast not done with any regularity. The scheduling information specified by the marketing person is packaged up into a ScheduleExpression, and the scheduleFlyer on the FlyerBean is invoked. The code for this bean is shown in the following listing.

Listing 7.4. FlyerBean implementation

The FlyerBean in this listing is responsible for scheduling the flyer for delivery and also sending the email when the timer expires. The TimerService is injected via an annotation . The method getScheduledFlyers has been implemented to drive a web page enabling someone in marketing to see which flyers have been scheduled for delivery . The scheduleFlyer method is responsible for scheduling the flyer. The user interface constructs an instance of ScheduleExpression that will ultimately be passed off to the TimerService. A TimerConfig instance is created to encapsulate the flyer and also specify that this timer should survive server restarts . A Timer is created inside the TimerService using the scheduling from the ScheduleExpression and the configuration from the TimerConfig . Once a Timer is created, information about it may be retrieved, such as the next time the timer will time out . The send method is annotated with @TimeOut to mark it as the method responsible for executing the task with the timer completes.

This example is straightforward. The TimerService creates timers that are associated with the current bean. The method to be invoked when the timer expires can either be marked with the @TimeOut annotation or by implementing the javax.ejb .TimedObject interface.

One important snippet of code that you’ve not yet seen is how to construct a ScheduleExpression. ScheduleExpression, as mentioned earlier, supports method chaining, thus reducing the number of lines of code necessary to specify a time. To construct an expression for sending out a flyer on Valentine’s day right before lunch, the following code snippet would construct the appropriate ScheduleExpression:

ScheduleExpression se = new ScheduleExpression();
se.month(2).dayOfMonth(14).year(2012).hour(11).minute(30); // 2/14/2012 @ 11:30

Using programmatic timers is thus relatively easy. You have the Timer Service injected into the bean, annotate a method in the bean with the javax.ejb.TimeOut, and schedule the method using one of the methods on the javax.ejb.TimerService object. This couldn’t be any easier!

7.3.3. Using EJB programmatic timers effectively

Programmatic timers enable operations to be scheduled programmatically at runtime. They’re great for user-driven operations like the example of scheduling a flyer. These are operations where you can’t predict when something will be scheduled. Another example in ActionBazaar would be the conclusion of bidding on an item. A programmatic timer could be used to close out bidding and mail the winning bidder notification of their triumph. When bidding is first opened, a new timer is created that will fire when the bidding is scheduled to conclude. Programmatic timers thus are versatile, and, unlike declarative timers, they’re fluid and can be created and changed at runtime without editing a configuration file or recompiling. In contrast, declarative timers should be used for operations that are known in development and perform an application maintenance task such as purging inactive accounts on a monthly basis.

When using programmatic timers, it’s important to consider how the timers are being persisted by the application container. Redeploying an application may wipe existing timers. This would probably be an unintended side effect if you were merely deploying a patch to fix a bug in production. Therefore, it’s important to understand how timer persistence is impacted by more than just server restarts/failures. What happens when an application is redeployed or migrated to another server? Application server developers have already tackled many of these issues, so it’s just a matter of investigating your container and precisely defining and understanding how the application will respond to different events besides just server restarts.

In addition to issues surrounding server restarts, one other consideration is making sure that the EJB scheduling facilities aren’t overused. It’s important to consider the granularity of the task. In the ActionBazaar application, the email address specified when creating a new account must be verified. If account verification doesn’t occur within 24 hours, the account is deleted—you don’t want the system polluted with unactivated accounts. Whether the cleanup of unactivated accounts happens at exactly at 24 hours, 24:30 hours, or even 25 hours later isn’t important. Thus, it would be overkill to use programmatic timers on each new account creation because deleting the account exactly at the specified time isn’t important. Instead, a better solution would be to use a declarative timer that fires every hour or every day and deletes accounts that haven’t been activated within the past 24 hours. Multiple accounts can be deleted within the same transaction, and the server isn’t busy tracking dozens of scheduled timers.

join today to enjoy all our content. all the time.
 

7.4. Summary

In this chapter we’ve delved into EJB’s scheduling capabilities. EJB 3.1 was a major leap forward from EJB 3 in terms of scheduling. With 3.1, EJB gained cron-like scheduling. Prior to EJB 3.1, serious scheduling requirements necessitated the use of third-party solutions such as Quartz. Bolting on external libraries is fraught with code complications and potential legal problems depending on the acceptability of the license. Thus, the new scheduling features are a major improvement.

As you’ve seen, the EJB scheduling capabilities can be broken down into declarative and programmatic. With declarative, annotations are placed on methods within stateless session beans to specify when the method should be executed and how often. Programmatic scheduling is done at runtime via the javax.ejb.TimerService object. Both declarative and programmatic scheduling support calendar-/cron-based scheduling in addition to the interval-based scheduling present in previous releases. Which approach is used depends on the task and whether it’s hardwired into the application or driven at runtime. In the next chapter we’ll switch gears and look at web services.

sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage
Up next...
  • The basics of web services
  • The basics of SOAP (JAX-WS)
  • Exposing EJBs as SOAP web services
  • The basics of REST (JAX-RS)
  • Exposing EJBs as RES web services
{{{UNSCRAMBLE_INFO_CONTENT}}}