ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Scheduling Jobs in a Java Web Application

by Chris Hardin
03/01/2006

In large J2EE web applications, a common task is scheduling tasks. Developers want to do all kinds of operations that can run at specified intervals and complete tasks that don't require user input. Java has a myriad of ways to accomplish this task, but there is no standard for doing this in a web application. This can become a great problem if you have many developers working on the same project and each of them decides to implement scheduling in his or her own way. Memory and synchronization issues are the first two things that come to mind when each developer rolls their own solution. In fact, some developers are tempted to make system calls to an operating-system-level scheduling mechanism like cron on Unix platforms. This is not only a bad programming practice, but it throws portability right out of the window.

Why Schedule?

In a web application, most tasks are accomplished in a manner that prevents the user from having to wait too long. Think of a Google search, for example. Keeping the user from waiting is extremely important for the sake of the user experience. One solution for asynchronous tasks is to spawn a thread after a user submits, but that doesn't really solve situations where the task needs to re-occur at specific intervals or run a certain time of the day every day.

Let's take an example of a database report and see how scheduling can help us in our application design. Reports can be intricate and complicated, depending on what kind of data a user wants to see and whether there is a ton of data aggregated into the report from a database or multiple databases. It could take a long time for a user to run an "on demand" report like this. So let's add a scheduling mechanism to our reporting example to allow a user to schedule the report for whenever he or she wants it and have it emailed to them as a PDF or in some other format. The user could schedule the report to run every day at 2:22 a.m., when the system might be in a less stressed state, or they might choose to run it just once, at a specific time. By adding scheduling to our reporting application, we can add a valuable feature and improve the user's experience of the product.

Luckily, there is a robust open source solution that works like a charm to standardize the way you conduct scheduling in a web application (or any other Java application, for that matter). The following examples will show you how to use Quartz, an open source scheduling library, to create a scheduling framework in your web application. The example also uses Struts Action framework plugins in order to initialize the scheduling mechanism when the web application starts. The Struts Action framework (or just "Struts") is a such a common framework that it should be familiar for most developers. Of course, there are many other frameworks available for Java web applications that facilitate a Model-View-Controller design pattern.

Initializing a Scheduler on Startup

The first thing we want to do is set up the Struts plugin to create our scheduler when the container starts. For these examples, it is assumed that Tomcat will be the web application container of choice, but the examples should work in any container. We will create a Struts plugin class and add some lines to the struts-config.xml file to get this going.

The plugin configuration has two properties used for initialization. startOnLoad specifies whether or not we want to start the scheduler immediately when the container starts and startupDelay is used to specify how long before the code will attempt to start the scheduler. The delay is important, because we might want to start the process after more important initialization steps. A listener mechanism could also be used here to provide a more sophisticated mechanism for notifying the SchedulerPlugIn to start the Quartz Scheduler.

  <plug-in className="SchedulerPlugIn">
     <set-property property="startOnLoad" value="false" />
     <set-property property="startupDelay" value="0" />
  </plug-in>

We are going to create a class of our own; the SchedulerPlugIn is merely a singleton class that implements the Struts interface org.apache.struts.action.PlugIn. Struts will instantiate plugins in the order in which they appear in the config file. The lines to pay particular attention to are from the init() method, where we instantiate our Quartz objects and get the Scheduler. The org.quartz.Scheduler object, which we will discuss later, is where we will submit our job information. The Scheduler will be instantiated by the Quartz servlet configuration, much like Struts initializes its ActionServlet class. Let's take a look at the init() method:


public void init(ActionServlet actionServlet,
                 ModuleConfig moduleConfig) {

  System.out.println("Initializing Scheduler PlugIn for Jobs!");
  // Retrieve the ServletContext
  ServletContext ctx = actionServlet.getServletContext();
  // The Quartz Scheduler
  Scheduler scheduler = null;

  // Retrieve the factory from the ServletContext.
  // It will be put there by the Quartz Servlet
  StdSchedulerFactory factory =  (StdSchedulerFactory) 
      ctx.getAttribute(QuartzInitializerServlet.QUARTZ_FACTORY_KEY);
    
  try{
        // Retrieve the scheduler from the factory
        scheduler = factory.getScheduler();

        // Start the scheduler in case, it isn't started yet
        if (m_startOnLoad != null && 
            m_startOnLoad.equals(Boolean.TRUE.toString())){
            System.out.println("Scheduler Will start in " +
            m_startupDelayString + " milliseconds!");
            //wait the specified amount of time before
            // starting the process.
            Thread delayedScheduler =
                new Thread(new DelayedSchedulerStarted (
                                   scheduler, m_startupDelay));
            //give the scheduler a name. All good code needs a name
            delayedScheduler.setName("Delayed_Scheduler");
            //Start out scheduler
            delayedScheduler.start();
        }
  } catch (Exception e){
     e.printStackTrace();
  }
    sm_scheduler = scheduler;
}
Real World Web Services

Related Reading

Real World Web Services
Integrating EBay, Google, Amazon, FedEx and more
By Will Iverson

Pages: 1, 2, 3

Next Pagearrow