Using the Timer Service (original) (raw)
Applications that model business work flows often rely on timed notifications. The timer service of the enterprise bean container enables you to schedule timed notifications for all types of enterprise beans except for stateful session beans. You can schedule a timed notification to occur according to a calendar schedule, at a specific time, after a duration of time, or at timed intervals. For example, you could set timers to go off at 10:30 a.m. on May 23, in 30 days, or every 12 hours.
Enterprise bean timers are either programmatic timers or automatic timers. Programmatic timers are set by explicitly calling one of the timer creation methods of the TimerService
interface. Automatic timers are created upon the successful deployment of an enterprise bean that contains a method annotated with the javax.ejb.Schedule
orjavax.ejb.Schedules
annotations.
Creating Calendar-Based Timer Expressions
Timers can be set according to a calendar-based schedule, expressed using a syntax similar to the UNIX cron
utility. Both programmatic and automatic timers can use calendar-based timer expressions.Table 37-1 shows the calendar-based timer attributes.
Table 37-1 Calendar-Based Timer Attributes
Attribute | Description | Default Value | Allowable Values and Examples |
---|---|---|---|
second | One or more seconds within a minute | 0 | 0 to 59. For example: second="30". |
minute | One or more minutes within an hour | 0 | 0 to 59. For example: minute="15". |
hour | One or more hours within a day | 0 | 0 to 23. For example:hour="13". |
dayOfWeek | One or more days within a week | * | 0 to 7 (both 0 and 7 refer to Sunday). For example: dayOfWeek="3". Sun, Mon, Tue, Wed, Thu, Fri, Sat. For example:dayOfWeek="Mon". |
dayOfMonth | One or more days within a month | * | 1 to 31. For example: dayOfMonth="15". –7 to –1 (a negative number means the nth day or days before the end of the month). For example: dayOfMonth="–3". Last. For example: dayOfMonth="Last". [1st, 2nd, 3rd, 4th, 5th, Last] [Sun, Mon, Tue, Wed,Thu, Fri, Sat]. For example: dayOfMonth="2nd Fri". |
month | One or more months within a year | * | 1 to 12. For example: month="7". Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct,Nov, Dec. For example: month="July". |
year | A particular calendar year | * | A four-digit calendar year. For example: year="2011". |
Specifying Multiple Values in Calendar Expressions
You can specify multiple values in calendar expressions, as described in the following sections.
Using Wildcards in Calendar Expressions
Setting an attribute to an asterisk symbol (*
) represents all allowable values for the attribute.
The following expression represents every minute:
The following expression represents every day of the week:
Specifying a List of Values
To specify two or more values for an attribute, use a comma (,
) to separate the values. A range of values is allowed as part of a list. Wildcards and intervals, however, are not allowed.
Duplicates within a list are ignored.
The following expression sets the day of the week to Tuesday and Thursday:
The following expression represents 4:00 a.m., every hour from 9:00 a.m. to 5:00 p.m. using a range, and 10:00 p.m.:
Specifying a Range of Values
Use a dash character (-
) to specify an inclusive range of values for an attribute. Members of a range cannot be wildcards, lists, or intervals. A range of the form x-x
, is equivalent to the single-valued expression x
. A range of the form x-y
where x
is greater than y
is equivalent to the expression x-`maximumvalue
,` minimumvalue`-y`. That is, the expression begins at x
, rolls over to the beginning of the allowable values, and continues up to y
.
The following expression represents 9:00 a.m. to 5:00 p.m.:
The following expression represents Friday through Monday:
The following expression represents the twenty-fifth day of the month to the end of the month, and the beginning of the month to the fifth day of the month:
It is equivalent to the following expression:
Specifying Intervals
The forward slash (/
) constrains an attribute to a starting point and an interval and is used to specify every N
seconds, minutes, or hours within the minute, hour, or day. For an expression of the form x/y
,x
represents the starting point and y
represents the interval. The wildcard character may be used in the x
position of an interval and is equivalent to setting x
to 0
.
Intervals may be set only for second
, minute
, and hour
attributes.
The following expression represents every 10 minutes within the hour:
It is equivalent to:
minute="0,10,20,30,40,50"
The following expression represents every 2 hours starting at noon:
Programmatic Timers
When a programmatic timer expires (goes off), the container calls the method annotated @Timeout
in the bean’s implementation class. The@Timeout
method contains the business logic that handles the timed event.
The @Timeout Method
Methods annotated @Timeout
in the enterprise bean class must returnvoid
and optionally take a javax.ejb.Timer
object as the only parameter. They may not throw application exceptions:
@Timeout
public void timeout(Timer timer) {
System.out.println("TimerBean: timeout occurred");
}
Creating Programmatic Timers
To create a timer, the bean invokes one of the create
methods of theTimerService
interface. These methods allow single-action, interval, or calendar-based timers to be created.
For single-action or interval timers, the expiration of the timer can be expressed as either a duration or an absolute time. The duration is expressed as a the number of milliseconds before a timeout event is triggered. To specify an absolute time, create a java.util.Date
object and pass it to the TimerService.createSingleActionTimer
or theTimerService.createTimer
method.
The following code sets a programmatic timer that will expire in 1 minute (60,000 milliseconds):
long duration = 60000;
Timer timer =
timerService.createSingleActionTimer(duration, new TimerConfig());
The following code sets a programmatic timer that will expire at 12:05 p.m. on May 1, 2015, specified as a java.util.Date
:
SimpleDateFormatter formatter =
new SimpleDateFormatter("MM/dd/yyyy 'at' HH:mm");
Date date = formatter.parse("05/01/2015 at 12:05");
Timer timer = timerService.createSingleActionTimer(date, new TimerConfig());
For calendar-based timers, the expiration of the timer is expressed as ajavax.ejb.ScheduleExpression
object, passed as a parameter to theTimerService.createCalendarTimer
method. The ScheduleExpression
class represents calendar-based timer expressions and has methods that correspond to the attributes described in Creating Calendar-Based Timer Expressions.
The following code creates a programmatic timer using theScheduleExpression
helper class:
ScheduleExpression schedule = new ScheduleExpression();
schedule.dayOfWeek("Mon");
schedule.hour("12-17, 23");
Timer timer = timerService.createCalendarTimer(schedule);
The bean described in The timersession Example creates a timer as follows:
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
In the timersession
example, the method that calls createTimer
is invoked in a business method, which is called by a client.
Timers are persistent by default. If the server is shut down or crashes, persistent timers are saved and will become active again when the server is restarted. If a persistent timer expires while the server is down, the container will call the @Timeout
method when the server is restarted.
Nonpersistent programmatic timers are created by callingTimerConfig.setPersistent(false)
and passing the TimerConfig
object to one of the timer-creation methods.
The Date
and long
parameters of the createTimer
methods represent time with the resolution of milliseconds. However, because the timer service is not intended for real-time applications, a callback to the@Timeout
method might not occur with millisecond precision. The timer service is for business applications, which typically measure time in hours, days, or longer durations.
Automatic Timers
Automatic timers are created by the EJB container when an enterprise bean that contains methods annotated with the @Schedule
or@Schedules
annotations is deployed. An enterprise bean can have multiple automatic timeout methods, unlike a programmatic timer, which allows only one method annotated with the @Timeout
annotation in the enterprise bean class.
Automatic timers can be configured through annotations or through theejb-jar.xml
deployment descriptor.
Adding a @Schedule
annotation on an enterprise bean marks that method as a timeout method according to the calendar schedule specified in the attributes of @Schedule
.
The @Schedule
annotation has elements that correspond to the calendar expressions detailed in Creating Calendar-Based Timer Expressions and the persistent
, info
, and timezone
elements.
The optional persistent
element takes a Boolean value and is used to specify whether the automatic timer should survive a server restart or crash. By default, all automatic timers are persistent.
The optional timezone
element is used to specify that the automatic timer is associated with a particular time zone. If set, this element will evaluate all timer expressions in relation to the specified time zone, regardless of the time zone in which the EJB container is running. By default, all automatic timers set are in relation to the default time zone of the server.
The optional info
element is used to set an informational description of the timer. A timer’s information can be retrieved later by usingTimer.getInfo
.
The following timeout method uses @Schedule
to set a timer that will expire every Sunday at midnight:
@Schedule(dayOfWeek="Sun", hour="0")
public void cleanupWeekData() { ... }
The @Schedules
annotation is used to specify multiple calendar-based timer expressions for a given timeout method.
The following timeout method uses the @Schedules
annotation to set multiple calendar-based timer expressions. The first expression sets a timer to expire on the last day of every month. The second expression sets a timer to expire every Friday at 11:00 p.m.:
@Schedules ({
@Schedule(dayOfMonth="Last"),
@Schedule(dayOfWeek="Fri", hour="23")
})
public void doPeriodicCleanup() { ... }
Canceling and Saving Timers
Timers can be cancelled by the following events.
- When a single-event timer expires, the EJB container calls the associated timeout method and then cancels the timer.
- When the bean invokes the
cancel
method of theTimer
interface, the container cancels the timer.
If a method is invoked on a cancelled timer, the container throws thejavax.ejb.NoSuchObjectLocalException
.
To save a Timer
object for future reference, invoke its getHandle
method and store the TimerHandle
object in a database. (ATimerHandle
object is serializable.) To reinstantiate the Timer
object, retrieve the handle from the database and invoke getTimer
on the handle. A TimerHandle
object cannot be passed as an argument of a method defined in a remote or web service interface. In other words, remote clients and web service clients cannot access a bean’sTimerHandle
object. Local clients, however, do not have this restriction.
Getting Timer Information
In addition to defining the cancel
and getHandle
methods, theTimer
interface defines methods for obtaining information about timers:
public long getTimeRemaining();
public java.util.Date getNextTimeout();
public java.io.Serializable getInfo();
The getInfo
method returns the object that was the last parameter of the createTimer
invocation. For example, in the createTimer
code snippet of the preceding section, this information parameter is aString
object with the value created timer
.
To retrieve all of a bean’s active timers, call the getTimers
method of the TimerService
interface. The getTimers
method returns a collection of Timer
objects.
Transactions and Timers
An enterprise bean usually creates a timer within a transaction. If this transaction is rolled back, the timer creation also is rolled back. Similarly, if a bean cancels a timer within a transaction that gets rolled back, the timer cancellation is rolled back. In this case, the timer’s duration is reset as if the cancellation had never occurred.
In beans that use container-managed transactions, the @Timeout
method usually has the Required
or RequiresNew
transaction attribute to preserve transaction integrity. With these attributes, the EJB container begins the new transaction before calling the @Timeout
method. If the transaction is rolled back, the container will call the @Timeout
method at least one more time.
The timersession Example
The source code for this example is in the_tut-install_/examples/ejb/timersession/src/main/java/
directory.
TimerSessionBean
is a singleton session bean that shows how to set both an automatic timer and a programmatic timer. In the source code listing of TimerSessionBean
that follows, the setTimer
and@Timeout
methods are used to set a programmatic timer. ATimerService
instance is injected by the container when the bean is created. Because it’s a business method, setTimer
is exposed to the local, no-interface view of TimerSessionBean
and can be invoked by the client. In this example, the client invokes setTimer
with an interval duration of 8,000 milliseconds, or 8 seconds. The setTimer
method creates a new timer by invoking the createTimer
method ofTimerService
. Now that the timer is set, the EJB container will invoke the programmaticTimeout
method of TimerSessionBean
when the timer expires, in about 8 seconds:
...
public void setTimer(long intervalDuration) {
logger.log(Level.INFO,
"Setting a programmatic timeout for {0} milliseconds from now.",
intervalDuration);
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
}
@Timeout
public void programmaticTimeout(Timer timer) {
this.setLastProgrammaticTimeout(new Date());
logger.info("Programmatic timeout occurred.");
}
...
TimerSessionBean
also has an automatic timer and timeout method,automaticTimeout
. The automatic timer is set to expire every 1 minute and is set by using a calendar-based timer expression in the @Schedule
annotation:
...
@Schedule(minute = "*/1", hour = "*", persistent = false)
public void automaticTimeout() {
this.setLastAutomaticTimeout(new Date());
logger.info("Automatic timeout occured");
}
...
TimerSessionBean
also has two business methods:getLastProgrammaticTimeout
and getLastAutomaticTimeout
. Clients call these methods to get the date and time of the last timeout for the programmatic timer and automatic timer, respectively.
Here’s the source code for the TimerSessionBean
class:
package javaeetutorial.timersession.ejb;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
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.TimerService;
@Singleton
@Startup
public class TimerSessionBean {
@Resource
TimerService timerService;
private Date lastProgrammaticTimeout;
private Date lastAutomaticTimeout;
private static final Logger logger =
Logger.getLogger("timersession.ejb.TimerSessionBean");
public void setTimer(long intervalDuration) {
logger.log(Level.INFO,
"Setting a programmatic timeout for {0} milliseconds from now.",
intervalDuration);
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
}
@Timeout
public void programmaticTimeout(Timer timer) {
this.setLastProgrammaticTimeout(new Date());
logger.info("Programmatic timeout occurred.");
}
@Schedule(minute = "*/1", hour = "*", persistent = false)
public void automaticTimeout() {
this.setLastAutomaticTimeout(new Date());
logger.info("Automatic timeout occured");
}
public String getLastProgrammaticTimeout() {
if (lastProgrammaticTimeout != null) {
return lastProgrammaticTimeout.toString();
} else {
return "never";
}
}
public void setLastProgrammaticTimeout(Date lastTimeout) {
this.lastProgrammaticTimeout = lastTimeout;
}
public String getLastAutomaticTimeout() {
if (lastAutomaticTimeout != null) {
return lastAutomaticTimeout.toString();
} else {
return "never";
}
}
public void setLastAutomaticTimeout(Date lastAutomaticTimeout) {
this.lastAutomaticTimeout = lastAutomaticTimeout;
}
}
Note: GlassFish Server has a default minimum timeout value of 1,000 milliseconds, or 1 second. If you need to set the timeout value lower than 1,000 milliseconds, change the value of the Minimum Delivery Interval setting in the Administration Console. To modify the minimum timeout value, in the Administration Console expand Configurations, then expand server-config, select EJB Container, and click the EJB Timer Service tab. Enter a new timeout value under Minimum Delivery Interval and click Save. The lowest practical value forminimum-delivery-interval-in-millis is around 10 milliseconds, owing to virtual machine constraints. |
---|
Running the timersession Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the timersession
example.
The following topics are addressed here:
- To Run the timersession Example Using NetBeans IDE
- To Build, Package, and Deploy the timersession Example Using Maven
- To Run the Web Client
To Run the timersession Example Using NetBeans IDE
- Make sure that GlassFish Server has been started (seeStarting and Stopping GlassFish Server).
- From the File menu, choose Open Project.
- In the Open Project dialog box, navigate to:
- Select the
timersession
folder. - Click Open Project.
- From the Run menu, choose Run Project.
This builds and packages the application into a WAR file located at_tut-install_/examples/ejb/timersession/target/timersession.war
, deploys this WAR file to your GlassFish Server instance, and then runs the web client.
To Build, Package, and Deploy the timersession Example Using Maven
- Make sure that GlassFish Server has been started (seeStarting and Stopping GlassFish Server).
- In a terminal window, go to:
tut-install/examples/ejb/timersession/
- Enter the following command:
This builds and packages the application into a WAR file located at_tut-install_/examples/ejb/timersession/target/timersession.war
and deploys this WAR file to your GlassFish Server instance.
To Run the Web Client
- Open a web browser to the following URL:
http://localhost:8080/timersession
- Click Set Timer to set a programmatic timer.
- Wait for a while and click the browser’s Refresh button.
You will see the date and time of the last programmatic and automatic timeouts.
To see the messages that are logged when a timeout occurs, open theserver.log
file located in domain-dir`/logs/`.