I have a project where I need to do something constantly, roughly every minute. There are a lot of ways for me to do this: Quartz, cron, jcrontab, a series of other projects and invocation mechanisms. However, Quartz bothers me because it creates threads, cron is non-Java... all things that, pragmatically speaking, I can tolerate, but if you have to use pragmatism as an excuse, the standard isn't sufficient.
With EJB 3, you have a Timer service, basically where you annotate a method with a @Timeout annotation, and that method is called on the EJB when the timer elapses. Sounds horribly useful, and exactly what I rather want, except for this:
Here's a slightly modified example from the JEE tutorial, with imports trimmed for space:
@Stateless
public class TimerSessionBean implements TimerSession {
@Resource
TimerService timerService;
public void createTimer(long intervalDuration) {
Timer timer = timerService.createTimer(intervalDuration, intervalDuration,
"Created new timer");
}
@Timeout
public void timeout(Timer timer) {
System.out.println("TimerBean: timeout occurred");
}
} The change is in the createTimer(long) method, where it uses the form of TimerService.createTimer() that creates recurring events (i.e., time out in "intervalDuration" milliseconds, and every "intervalDuration" milliseconds later.) So for events that should happen every minute, I'd simply call createTimer(60000L), right?
Ah, here's where the problems start. From where? The example uses a handy-dandy application client, which gets a reference to the stateless session bean via injection (i.e., @EJB TimerSessionBean timerbean;) and it then calls timerbean.createTimer(30000);.
The problem is that I want this to start when I deploy and start the application. I don't want an explicit "start" mechanism.
I could always use a servlet, loaded on startup, but I don't know how the application shutdown (or deactivation) is supposed to affect the threads - if I redeploy the .war without necessarily deactivating everything associated with the .ear, am I looking at two event timers? I hope not.
What would be really nice is if the specification mandated that timers were server-managed resources (like, oh, queues?) and allowed me to say "TimerBean will get a single (or recurring) event every 30000 milliseconds," and I'd leave the application code out of it altogether.
Of course, maybe I'm just misinformed. I don't know, but I think if it's really as easy as I think it should be, this should be clearly documented somewhere.
What I've done is used an app startup servlet to remove all existing timers
for that class and then create a new one. Not the prettiest solution but
obtains the necessary behaviour.
Consider putting this in a (dedicated) ServletContextListener, e.g
public void contextInitialized(ServletContextEvent sce){
doStuff();
}
Yes, I have the same problem and now I'm getting two timers firing on my
server. Sigh - created a big mess for me to clean up. I'd hardly call JPA
a pleasant experience to use, but I think (I hope!) they're still working
on making it more usable.