Recently, I had the need to create a task that had to run hourly, with the stats to be available to clients. I wanted the task to be distributed without having to worry about configuring a database store, etc.
The solution I came up with was to create a JAVA servlet and use a Timer object to schedule a timer task that runs every hour. The task then runs hourly and saves the results in memory.
Usually, creating threads (which is what a TimerTask object is) in a servlet container is frowned upon because the container cannot manage the resources used by the user spawned thread. In addition, whenever your web application is deployed, reloaded, or undeployed you have to ensure that you clean up after your thread.
The first thing that you will do is implement the ServletContextListener interface. This interface consist of 2 methods that you will have to implement, namely,
public void contextInitialized (ServletContextEvent servletContextEvent);
&
public void contextDestroyed (ServletContextEvent servletContextEvent);
The contextInitialized(...) method is invoked by the servlet container everytime the servlet is 'started up'. So upon initial deployment, this method is called. Everytime you reload your web application, this method is invoked.
The contextDestroyed(...) method is invoked everytime the web application is shut down, for example, when you reload or un-deploy the web application.
Ideally, anything that you need to do when the web application first starts up should be done in the contextInitialized(...) method, while anything to undo the initialization should be done in the contextDestroyed(...) method.
In the contextInitialized(...) method, the idea is to create a TimerTask object and using the Timer object, schedule it at the desired time interval. Once the scheduling is done, we save the Timer object as an attribute in the ServletContext.
For example, assuming that MyTimerTask extends TimerTask,
ServletContext servletContext = servletContextEvent.getServletContext();
try{
// create the timer and timer task objects
Timer timer = new Timer();
MyTimerTask task = new MyTimerTask();
// get a calendar to initialize the start time
Calendar calendar = Calendar.getInstance();
Date startTime = calendar.getTime();
// schedule the task to run hourly
timer.scheduleAtFixedRate(task, startTime, 1000 * 60 * 60);
// save our timer for later use
servletContext.setAttribute ("timer", timer);
} catch (Exception e) {
servletContext.log ("Problem initializing the task that was to run hourly: " + e.getMessage ());
}
In the contextDestroyed(...) method, the idea is to clean up after yourself. In our case, this means cancelling any tasks and removing the timer object.
The final thing that we have to do now is make sure that our ServletContextListener is added to our web.xml file.
ServletContext servletContext = servletContextEvent.getServletContext();
// get our timer from the Context
Timer timer = (Timer)servletContext.getAttribute ("timer");
// cancel all pending tasks in the timers queue
if (timer != null)
timer.cancel();
// remove the timer from the servlet context
servletContext.removeAttribute ("timer");
As a child element of the <web-app> element, add the following lines of code:
<listener>
<listener-class>your.package.declaration.MyServletContextListener</listener-class>
</listener>
Where, your.package.declaration is the package containing the class MyServletContextListener that implements ServletContextListener!
Now everytime the web application starts up and shuts down, our listener will be invoked. Not only did we create an on-going task, but we scheduled the task and made sure that we cleaned up after ourselves too!
13 comments:
Very nice. It's not technically JEE compliant, but it works, which is what I'm more concerned with. Thanks!
Having implemented ServletContextListener... any clue why my Tomcat (5.5.17) shuts down when I stop/reload my application?? Very strange and unwished behaviour!
When did this behaviour occur? What happens if you remove your context listener? Does it still shut down tomcat? Can we see your listener?
Error found:
One always running job in the scheduler (receiving telegrams from a DB) was finished by System.exit().
This shut down Tomcat, too.
Yeah, System.exit() will shut down tomcat, as you may have noticed!
Thanks so much for this. Clean and simple.
Nice work.
nice work
it helped a lot
This was a great help, thank you very much.
Thanks, this helped alot. Thanks for keeping it on the web.
Very nice! This is exactly what I am looking for in my app! I have a process that needs to run once daily. Perfect solution!
Does init() and destory() methods of Servlet is not proper place to initialise and clenup Timer object?
The key thing to take home is that the Context init parameters are available to the entire web application and not just to a single servlet like servlet init parameters.
So I guess it depends on what you are trying to accomplish.
Hello there I am so excited I found your webpage, I really found you
by error, while I was looking on Askjeeve for something else, Regardless I am here now
and would just like to say thanks for a marvelous post and a all round
entertaining blog (I also love the theme/design), I don’t have time
to read it all at the moment but I have saved
it and also included your RSS feeds, so when I have time
I will be back to read more, Please do keep up the superb work.
Post a Comment