User would be able to start or stop a scheduler which do certain processing using the specified timer schedule. Here is a simple example of a programmatic EJB Timer.
In this example, it is assumed that the application have a SessionBean facade(s) which have all the business methods. A SessionBean facade is required for making use of the container managed persistence context in the business methods. The timer just invokes the relevant business method based on the timer schedule expiration.
package
com.prasune.ejb.timer;
import
java.util.Date;
import
javax.annotation.Resource;
import
javax.ejb.EJB;
import
javax.ejb.ScheduleExpression;
import
javax.ejb.Stateless;
import
javax.ejb.Timeout;
import
javax.ejb.Timer;
import
javax.ejb.TimerConfig;
import
javax.ejb.TimerService;
import
com.prasune.ejb.persistence.JPASessionFacade;
@Stateless(name = "ProgramaticTimer", mappedName =
"ProgramaticTimer")
public class ProgramaticTimerBean
implements
ProgramaticTimer {
@Resource
TimerService timerService;
@EJB
private
JPASessionFacade jpaSessionFacade;
public
ProgramaticTimerBean() {
}
@Timeout
public void
doProcess(Timer timer) {
System.out.println("Programatic
Timer got invoked at " + new Date());
jpaSessionFacade.dmlOperation();
}
public void
startScheduler(){
ScheduleExpression scheduleExpression
= new ScheduleExpression();
scheduleExpression.hour("*").minute("*").second("*/5");
timerService.createCalendarTimer(scheduleExpression,
new TimerConfig("TestTimer", true));
System.out.println("Programatic
Timer got created succesfully");
}
public void
stopScheduler(String schedulerId) {
if (timerService.getTimers()
!= null) {
for (Timer timer
: timerService.getTimers())
{
if
(timer.getInfo().equals(schedulerId)) {
timer.cancel();
System.out.println("Programatic
Timer got stopped succesfully");
}
}
}
}
}
|
startScheduler() method creates a timer using the calendar based ejb ScheduleExpression.
The ScheduleExpression is very similar to chrone job schedule expression. Detailed usage of the ScheduleExpression for creating a timer can be found at Understanding EJB Timer Service 3.1.
In the example, we are creating a timer schedule to be executed every 5 seconds from now.
TimerConfig: There is an optional TimerConfig that can be passed while creating the calendar based timer. In the TimerConfig, we can specify an info like an Id using which we can identify the Timer. The Timer needs to be identified for stopping it as and when the user requires to do the same.The second parameter of the TimerConfig decides whether the Timer Schedule needs to be persisted or not. This is by default true and it means that the schedule of the timer is persisted and is not specific to JVM. Hence, it can survive a server crash.
@Resource annotation is used by the JEE server to inject the TimerService to the EJB.
@Timeout annotation is used to mark the method to be executed on timer schedule expiration. A programmatic Timer can have only one method with this annotation per EJB. The doProcess() method executes the relevant business method specified from the SessionBean facade.
@EJB annotation is used by the JEE server for injecting the SessionBean facade for calling the relevant business method.
stopScheduler() method fetches the Timers registered with TimerService and uses the TimerConfig info to identify the relevant timer and stops it.
ProgramaticTimer is the Local and Remote interface of the EJB. Although it is not mandatory to have a separate interface and the EJB can be annotated with Local/Remote annotations, it is better to program to interface. This will help while multiple applications are involved as the integrator needs to be given only the interface.
package
com.prasune.ejb.timer;
import
javax.ejb.Local;
import
javax.ejb.Remote;
@Local
@Remote
public interface
ProgramaticTimer {
public void
startScheduler();
public void
stopScheduler(String schedulerId);
}
|
ProgramaticTimerRemoteClient is a sample remote client for invoking the timer application to see if it is working fine. The example client uses Weblogic server initial context. The ProgramaticTimerBean APIs can be called for starting/stopping the scheduler and to verify whether it is working fine.
package
com.prasune.ejb.timer.client;
import
com.prasune.ejb.timer.ProgramaticTimer;
import
java.util.Hashtable;
import
javax.naming.CommunicationException;
import
javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.naming.NamingException;
public class
ProgramaticTimerRemoteClient {
public static void main(String[]
args) {
try {
final Context
context = getInitialContext();
ProgramaticTimer programaticTimer
=
(ProgramaticTimer)
context.lookup("ProgramaticTimer#com.prasune.ejb.timer.ProgramaticTimer");
programaticTimer.startScheduler();
//programaticTimer.stopScheduler("TestTimer");
System.out.println("Invoked
Timer");
} catch
(CommunicationException ex) {
System.out.println(ex.getClass().getName());
System.out.println(ex.getRootCause().getLocalizedMessage());
System.out.println("\n***
A CommunicationException was raised.
This typically\n*** occurs when the target WebLogic server is not
running.\n");
} catch (Exception
ex) {
ex.printStackTrace();
}
}
private static Context
getInitialContext() throws NamingException {
Hashtable env = new Hashtable();
// WebLogic Server 10.x/12.x
connection details
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7101");
return new
InitialContext(env);
}
}
|
Packaging and Deployment
Packaging and deployment of an EJB 3.1 Timer is very simple. The class file needs to be in a jar file with the correct directory structure of the package and the jar file can be directly deployed on any JEE server supporting EJB 3.1. The vendor specific ejb-jar.xml are optional and annotations are sufficient for the JEE server to identify the class as EJB Timer
No comments:
Post a Comment