Feb. 17, 2007, 2:51 p.m.
posted by hashspark
Message-Driven Bean TimersMessage-driven bean timers are similar to stateless session bean timers in several ways. Timers are associated only with the type of bean. When a timer expires, a message-driven bean instance is selected from a pool to execute the timeout callback method. In addition, message-driven beans can be used for performing audits or other types of batch jobs. The primary difference between a message-driven bean timer and a stateless session bean timer is the way in which they're initiated: timers are created in response to an incoming message or, if the container supports it, from a configuration file. In order to initialize a message-driven bean timer from an incoming message, you simply put the call to the TimerService.createTimer( ) method in the message-handling method. For a JMS-based message-driven bean, the method call goes in the onMessage( ) method:
@MessageDriven
public class JmsTimerBean implements MessageListener {
@Resource TimerService timerService
public void onMessage(Message message){
MapMessage mapMessage = (MapMessage)message;
long expirationDate = mapMessage.getLong("expirationDate");
timerService.createTimer(expirationDate, null );
}
@Timeout
public void timeout( ){
// put timeout logic here
}
The incoming JMS message should contain information about the timer: the beginning (start) date, duration, or even the Serializable info object. Combining JMS with the Timer Service can offer some powerful design options for implementing audits, batch processing, and agent-like solutions. Although it's not standardized, it is possible that vendors will allow message-driven bean timers to be configured at deployment time. This would require a proprietary solution, since standard configuration options for message-driven bean timers do not exist. The advantage of configured timers is that they do not require a client to initiate some action to start the timer. When the bean is deployed, its timer is set automatically. This capability makes message-driven bean timers more like Unix cron jobs, which are preconfigured and then run. Consult your vendor to see if it offers a proprietary configuration for message-driven bean timers. As was the case for stateless session beans, the TimedObject interface or the presence of an @Timeout method changes the life cycle of the message-driven bean slightly (see Figure). When a timed event occurs, the container must pull a message-driven bean instance from the pool. If there are no instances in the pool, then an instance must be moved from the Does Not Exist state to the Method-Ready Pool before it can receive the timed event. Problems with the Timer ServiceThe Timer Service is an excellent addition to the EJB platform, but it's limited. A lot can be learned from cron, the Unix scheduling utility that's been around for years. Here are some proposals for improving the service. If you are interested only in learning how timers work now, as opposed to how they may be improved, feel free to skip the rest of this chapterit's not required reading. With that said, understanding how timers can be improved helps you understand their limitations. If you have some time and want to expand your understanding of timers, keep reading. message-driven bean lifecycle with TimedObject![]() A very little bit about cronCron is a Unix program that allows you to schedule scripts (similar to batch files in DOS), commands, and other programs to run at specified dates and times. Unlike the EJB Timer Service, cron allows for flexible, calendar-based scheduling. Cron jobs (anything cron runs is called a job) can be scheduled to run at intervals, including a specific minute of the hour, hour of the day, day of the week, day of the month, and month of the year. For example, you can schedule a cron job to run every Friday at 12:15 p.m., or every hour, or the first day of every month. While this level of refinement may sound complicated, it is actually very easy to specify. Cron uses a simple text format of five fields of integer values, separated by spaces or tabs, to describe the intervals at which scripts should be run. Figure shows the field positions and their meanings. Cron date/time format![]() The order of the fields is significant, since each specifies a different calendar designator: minute, hour, day, month, and day of the week. The following examples show how to schedule cron jobs: 20 * * * * ---> 20 minutes after every hour. (00:20, 01:20, etc.) 5 22 * * * ---> Every day at 10:05 p.m. 0 8 1 * * ---> The first day of every month at 8:00 a.m. 0 8 4 7 * ---> The fourth of July at 8:00 a.m. 15 12 * * 5 ---> Every Friday at 12:15 p.m. An asterisk indicates that all values are valid. For example, if you use an asterisk for the minute field, you're scheduling cron to execute the job every minute of the hour. You can define more complex intervals by specifying multiple values, separated by commas, for a single field. In addition, you can specify ranges of time using the hyphen: 0 8 * * 1,3,5 ---> Every Monday, Wednesday, and Friday at 8:00 a.m. 0 8 1,15 * * ---> The first and 15th of every month at 8:00 a.m. 0 8-17 * * 1-5 ---> Every hour from 8:00 a.m. through 5:00 p.m., Mon-Fri. Cron jobs are scheduled using crontab files, which are simply text files in which you configure the date/time fields and a commandusually a command to run a script. Improving the Timer ServiceThe cron date/time format provides a lot more flexibility than is currently offered by the EJB Timer Service. The Timer Service requires you to designate intervals in exact milliseconds, which is a bit awkward to work with (you have to convert days, hours, and minutes to milliseconds), but more importantly, it's not flexible enough for many real-world scheduling needs. For example, there is no way to schedule a timer to expire on the first and 15th of every month, or every hour between 8:00 a.m. and 5:00 p.m., Monday through Friday. You can derive some of the more complex intervals but only at the cost of adding logic to your bean code to calculate them, and in more complicated scenarios, you'll need multiple timers for the same task. Cron is not perfect either. Scheduling jobs is like setting a timer on a VCR: everything is scheduled according to the clock and calendar. You can specify that cron run a job at specific times of the day on specific days of the year, but you can't have it run a job at relative intervals from an arbitrary starting point. For example, cron's date/time format doesn't let you schedule a job to run every 10 minutes, starting now. You have to schedule it to run at specific minutes of the hour (e.g., 0, 10, 20, 30, 40, 50). Cron is also limited to scheduling recurring jobs; you can't set up a single-action timer, and you can't set a start date. A problem with both cron and the EJB Timer Service is that you can't program a stop datea date when the timer will automatically cancel itself. You also may have noticed that cron granularity is to the minute rather than to the millisecond. At first glance, this looks like a weakness, but in practice, it's perfectly acceptable. For calendar-driven scheduling, more precision simply isn't very useful. The Timer Service interface would be improved if it could handle a cron-like date/time format, with a start date and end date. Instead of discarding the current createTimer( ) calls (which are useful, especially for single-action timers and arbitrary millisecond intervals), it would be preferable simply to add a new method with cron-like semantics. Instead of using 0-6 to designate the day of the week, it would be better to use the values Sun, Mon, Tue, Wed, Thu, Fri, and Sat (as in the Linux version of cron). For example, code to schedule a timer that would run every weekday at 11:00 p.m. starting October 1, 2006 and ending May 31, 2007 would look like this: TimerService timerService = ejbContext.getTimerService( ); Calendar start = Calendar.getInstance( ).set(2006, Calendar.OCTOBER, 1); Calendar end = Calendar.getInstance( ).set(2007, Calendar.MAY, 31); String dateTimeString = "23 * * * Mon-Fri"; timerService.createTimer(dateTimeString, start, end, null); This proposed change to the Timer Service retains the millisecond-based createTimer( ) methods because they are very useful. While cron-like configuration is powerful, it's not a silver bullet. If you need to schedule a timer to go off every 30 seconds starting now (or at any arbitrary point in time), you need to use one of the existing createTimer( ) methods. True millisecond accuracy is difficult; first, normal processing and thread contention tend to delay response time, and second, a server clock must be properly synchronized with the correct time (i.e., UTC)[*] to the millisecond, and most are not.
Message-driven beans: standard configuration propertiesAlthough the previous suggestions would improve usability a bit, they are not crucial for the use of an EJB timer. There is enormous potential for using message-driven beans as cron-like jobs that are configured at deployment and run automatically. Unfortunately, there is no standard way to configure a message-driven bean timer at deployment time. Some vendors may support this, but others do not. Preconfigured message-driven bean timers are going to be in high demand by developers who want to schedule message-driven beans to perform work at specific dates and times. Without support for deployment-time configuration, the only reliable way to program an enterprise bean timer is to have a client call a method or send a JMS message. This is not an acceptable solution. Developers need deployment-time configuration, and it should be added to the next version of the specification. Building on the cron-like semantics proposed in the previous subsection, it would be easy to devise standard activation properties for configuring message-driven bean timers at deployment time. For example, the following code configures a message-driven bean, the Audit EJB, to run at 11:00 p.m., Monday through Friday, starting October 1, 2006 and ending May 31, 2007 (start and end dates are not required):
<activation-config>
<description>Run Monday through Friday at 11:00 p.m.
Starting on Oct 1st,2003 until May 31st, 2004</description>
<activation-config-property>
<activation-config-property-name>dateTimeFields
</activation-config-property-name>
<activation-config-property-value> 23 * * * Mon-Fri
</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>startDate</activation-config-property-name>
<activation-config-property-value>October 1, 2003
</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>endDate</activation-config-property-name>
<activation-config-property-value>May 31, 2004
</activation-config-property-value>
</activation-config-property>
</activation-config>
This type of configuration would be fairly easy for providers to implement if they supported enhanced cron-like semantics. In addition, you could configure message-driven beans to use the millisecond-based timers EJB 2.1 already supports. Other problems with the Timer APIThe semantics of the Timer object convey little information about the object itself. There is no way to determine whether a timer is a single-action timer or an interval timer. If it's an interval timer, there is no way to determine the configured interval or whether the timer has executed its first expiration. To solve these problems, additional methods should be added to the Timer interface to provide this information. As a stopgap, it's a good idea to place this information in the info object so that it can be accessed by applications that need it. |
- Comment

