Sunday, March 17, 2013

Timer Service Using EJB 3.1

In the last post, we saw how to have scheduled processing using JBoss. The scheduling was very specific to JBoss. Let's look at how can we schedule using EJB 3.1. J2EE providers provided us with the EJB timers as alternative to threads for the timed notifications. We can schedule them like crontab in UNIX by specifying the day, hours, minutes, seconds to the service get invoked by the container.
The following example demonstrates how to use the EJB Timer service. I have created a very simple EJB application with one Stateless bean service which is being invoked by the Timer Service of the EJB.
  • Create a class with a call back method. Annotate the method with "Schedule" to make the method being called by the TimerService of EJB.
package com.test.ejb.timer;

import javax.ejb.EJB;
import javax.ejb.Schedule;
import javax.ejb.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.test.ejb.stateless.SimpleStatelessService;

@Singleton
public class SimpleTimer {
 
     private static final Logger LOG = LoggerFactory.getLogger(SimpleTimer.class);
     
     @EJB
     SimpleStatelessService service;
     
     @Schedule(hour="*", minute="*", second="10")
     public void startTimer() {
          LOG.info("Timer started... Invoking the bean");
          service.invokeBeanMethod();
     }    
}
The attributes inside the Schedule annotation are as follows
AttributeDescriptionValue
secondOne or more seconds within a minute0 to 59, default is 0
minuteOne or more minutes within an hour0 to 59, default is 0
hourOne or more hours within a day0 to 23, default is 0
dayOfWeekOne or more days within a week0 to 7 (Sunday to Sunday) default is * (Everyday). Even Mon, Tue etc are allowed
dayOfMonthOne or more days within a month1 to 31. Default is *. (Negative values are accepted, -5 means 5th day from end of the month)
monthOne or more months within a year1 to 12. Default is *. Names of the months are also allowed like Jan, Feb etc
yearA particular calendar yearA four digit year. Default is *
  • I have created a simple stateless bean named "SimpleStatelessSerive" to be invoked by the TimerService from the callback method startTimer().
package com.test.ejb.stateless;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Session Bean implementation class SimpleStatelessService
 */
@Stateless
@LocalBean
public class SimpleStatelessService {
     private static final Logger LOG = LoggerFactory.getLogger(SimpleStatelessService.class);
    /**
     * Default constructor. 
     */
    public SimpleStatelessService() {
        LOG.info("Service Created....");
    }
    public void invokeBeanMethod()
    {
         LOG.info("Inside invokeBean method");
    }
}
  • Deploy the EJB application onto Application server. I deployed it on Jboss6. The timer service started and invoking the callback method for every 10th second of the each minute as specified in the Schedule annotation.
Glimpse of the server log is
14:28:10,010 INFO  [com.test.ejb.timer.SimpleTimer] Timer started... Invoking the bean
14:28:10,011 INFO  [com.test.ejb.stateless.SimpleStatelessService] Service Created....
14:28:10,011 INFO  [com.test.ejb.stateless.SimpleStatelessService] Inside invokeBean method
14:29:10,009 INFO  [com.test.ejb.timer.SimpleTimer] Timer started... Invoking the bean
14:29:10,010 INFO  [com.test.ejb.stateless.SimpleStatelessService] Service Created....
14:29:10,010 INFO  [com.test.ejb.stateless.SimpleStatelessService] Inside invokeBean method

We can configure multiple callback methods for scheduling and each callback can be scheduled for multiple times. Have a look at the following sample code with two callback methods configured for Scheduling.
package com.test.ejb.timer;

import javax.ejb.EJB;
import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.test.ejb.stateless.SimpleStatelessService;

@Singleton
public class SimpleTimer {
     private static final Logger LOG = LoggerFactory.getLogger(SimpleTimer.class);  
     @EJB
     SimpleStatelessService service;
     
     @Schedules( {
          @Schedule(hour="*", minute="*", second="10"),
          @Schedule(hour="*", minute="*", second="13")
     })
     public void startTimer() {
          LOG.info("Timer started... Invoking the bean");
          service.invokeBean();
     }
     
     @Schedule(minute="3")
     public void antoherTimer() {
          LOG.info("Another Timer started.. Invoking the bean");
          service.invokeBean();
     }
}
There are two schedulers configured now.
  1. The startTimer() method is being configured for two scheduled times. One is every 10th second of the minute and the other is every 13th second of the minute. 
  2. The anotherTimer() which is being called every 3rd minute of the hour.