Quartz Job Scheduler and Manager

JavaDoc for Quartz

Find Quartz functional documentation at quartz.sourceforge.net/javadoc/. The Quartz home page is at www.opensymphony.com/quartz. Quartz JARs are downloadable from www.opensymphony.com/quartz/download.action.

Introduction to Quartz

Quartz is a Open Source job manager/scheduler (org.quartz. ...) for use in creating, managing and executing tens, hundreds or even tens-of-thousands of jobs. Quartz is freely licensed under Apache. The formal name is Quartz Enterprise Job Scheduler. A good essay on Quartz is found at javaboutique.internet.com/reviews/quartz. There is some good sample code here.*

Quartz is an implementation that obviates the need to program a pile of code to the Java Timer API. Quartz abstracts the scheduling process from application code, furnishes event and call-back mechanisms to monitor and modify the scheduled tasks, permits grouping and management of jobs according to their roles, and supports third-party plug-ins and components.

Quartz is easy-to-use. At any point in the development process, it can be plugged into the application code, wired up and used, behaving just as any other user API.

Using Quartz

Quartz has a scheduler engine that manages queued tasks. Once a task is queued, Quartz assigns a thread from its predefined pool to execute it. Thus, Quartz will multitask (multithread) tasks. Task code must therefore be reentrant.

Trade-offs are: insufficient threads in the pool for the number and rate of jobs (tasks) created and enqueued (bottleneck) and too many threads in the pool for the number of tasks (wasting resources and degrading system performance).

The Quartz scheduler works out of stores based either in memory or in database entries.


* Sample code warning: the tutorial doesn't say, but you need the Quartz JAR, the Apache commons JARs for logging and collections (on the path lib/core in the Quartz download material. If you're missing the first Apache JAR, you'll get an exception about missing the logging stuff. If you're missing the second, you'll get a mysterious message because you'll be using Java's SetUtil class instead of Apache's, which is very different.


In this pictorial, blue represents user code while white represents Quartz classes.

Algorithmically...

This reduces basic use of Quartz to an exceedingly simple example.

To use Quartz, a schedule is created, then a trigger, job details are added and the schedule is submitted. Here is a pseudocode fragment for the calling method that sets this all up. In this case, the job uses a simple trigger causing it to fire only once. We'll call the job "dummy" and create the classes accordingly. What's in bold type emphasizes our private (Dummy) consumption of Quartz.

	import java.util.Date;
	import java.util.Calendar;
	import org.quartz.Trigger;
	import org.quartz.Scheduler;
	import org.quartz.SchedulerException;
	import org.quartz.impl.StdSchedulerFactory;

	private static long id = 0;

	try
	{
	  Scheduler        scheduler = StdSchedulerFactory.getDefaultScheduler();
	  DummyJobDetail jobDetail = new DummyJobDetail( "dummy", null, DummyJob.class );

	  // calculate moment when the job should fire: let's try 20 seconds from now
	  Calendar  now     = Calendar.getInstance();
	  long      seconds = now.getTimeInMillis() / 1000;
	  Date      fire    = new Date( ( seconds + 20 ) * 1000 );

	  // set up trigger
	  Trigger trigger = new SimpleTrigger( "dummy job", "dummy group", fire );

	  jobDetail.setJobId( ++id );
	  scheduler.start();
	  scheduler.scheduleJob( jobDetail, trigger );
	}
	catch( SchedulerException schedulerException )
	{
	  schedulerException.printStackTrace();
	}

The dummy job details barely extends the Quartz class just to demonstrate how private use of Quartz happens. The job detail isn't the job itself, but only a means to help create a job and, perhaps, to get information about it later. (Not all the details of extending JobDetail are here.)

	import org.quartz.JobDetail;

	public class DummyJobDetail extends JobDetail
	{
	  private long jobId = 0;

	  public DummyJobDetail( String name, String group, Class< DummyJob > jobClass )
	  {
	    super( name, group, jobClass );
	  }

	  ...

	  public String getJobId() { return this.jobId; }
	  public void setJobId( String jobId ) { this.jobId = jobId; }
	}

Finally, here's the job itself. The important points in this code are a) that it implements execute() as required to implement the Quartz interface Job, and b) that the job detail, even the private, Dummy one, is available to it.

	import java.text.SimpleDateFormat;
	import java.util.Calendar;
	import java.util.Date;
	import org.quartz.Job;
	import org.quartz.JobExecutionContext;

	public class DummyJob implements Job
	{
	  private static final String  DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";

	  public void execute( JobExecutionContext context )
	  {
	    DummyJobDetail jobDetail = ( DummyJobDetail ) context.getJobDetail();

	    Calendar          cal = Calendar.getInstance();
	    SimpleDateFormat  sdf = new SimpleDateFormat( DATE_FORMAT_NOW );
	    String            now = sdf.format( cal.getTime() );
	    System.out.print( "Job "
	                      + jobDetail.getName()
	                      + " ("
	                      + jobDetail.getJobId()
	                      + ") began to fire at "
	                      + now );
	    // do whatever job does starting here...
	  }
	}