opencodez

Quartz – Java Job Scheduling Service

Most of the Java Projects, Enterprise Applications need some form of scheduling every now and then. People try to implement in number of ways like Timer, EJB etc. In one of my assignments I stumbled up on very interesting scheduling service known as Quartz. I was amazed by its simple but powerful implementation. Most interestingly its open source and can be integrated with virtually any Java application from the stand-alone application to the e-commerce system. Quartz supports all types of schedules, you can configure your timings from milliseconds to days to years. Quartz stands apart from other scheduling services by providing some state of the art features like Job Persistence, Transaction Support, Job Clustering, Listener Support.

Installation: Quartz get installed in matter of minutes. Only you have to download the latest jars that are available on their official site and add it to your project or application. Thatxs it!

Quartz allows you to divide your task in Job and run this job as per the schedule you have configured. You can uses a configuration/properties file to read the schedule. Sample properties file is shown below

#Extraction Frequency, (DAILY, WEEKLY, MONTHLY, HOURLY) 
FREQUENCY = DAILY

#Day of the month in case frequency is MONTHLY
DAY_OF_MONTH = 15

#Day of the week in case frequency is WEEKLY
DAY_OF_WEEK = 1

#Hour and Minute of the day for all frequencies except HOURLY(24 Hrs Format)
HOUR = 20
MIN =  05

In ideal scenario, you would need a scheduler class and a job to schedule. Here I am providing sample scheduler and job which is executed by trigger we create as Hourly.

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;

import com.mycompany.MyJob;

public class MYScheduler {

    public static java.util.Properties props = new java.util.Properties();

    static {

        try {
            java.io.FileInputStream fis = new java.io.FileInputStream(new java.io.File("configuration.properties"));
            props.load(fis);
            fis.close();

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
            System.exit(1);
        }
    }

    public static String FREQUENCY = props.getProperty("FREQUENCY");
    public static int DAY_OF_MONTH = Integer.parseInt(props.getProperty("DAY_OF_MONTH"));
    public static int DAY_OF_WEEK = Integer.parseInt(props.getProperty("DAY_OF_WEEK"));
    public static int HOUR = Integer.parseInt(props.getProperty("HOUR"));
    public static int MIN = Integer.parseInt(props.getProperty("MIN"));

    /**
     * @param args
     */
    public static void main(String[] args) {

        MYScheduler scheduler = new MYScheduler();
        try {
            scheduler.schedule();
        } catch (Exception e) {

        }
    }    

    public void schedule() throws Exception  {

        JobDetail myJob = MyJob.getJob();

        Trigger myTrigger = TriggerUtils.makeDailyTrigger("myTrigger", HOUR, MIN);

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();  

        MyJobListener listener = new MyJobListener();
        scheduler.addJobListener(listener);

        myJob.addJobListener(listener.getName());

        scheduler.start();
        scheduler.scheduleJob(myJob, myTrigger);

    }
}

Above scheduler class is creating an instance of job and a trigger to schedule the job. Job names are used so that job is uniquely identified in the schedule context. Here you will see that I am also trying to add the listener to the job. This is helpful when you want to do some another job once this is job is complete. e.g ETL. Here is the job and listener classes.
MyJob.java

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class MyJob implements Job {

    private final static String CLASS_NAME = MyJob.class.getName();
    private final static String JOB_NAME = "MyJob";

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        final String METHOD_NAME = "execute";

        //perform your actual task here

    }

    public static JobDetail getETLJob() {
        return new JobDetail(JOB_NAME, DGMEConstants.ETL_EXTRACTION_GROUP, MyJob.class);
    }

    public static String getJobName() {
        return JOB_NAME;
    }
}

MyJobListener.java

import java.util.Date;

import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.SchedulerContext;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;

public class MyJobListener implements JobListener  {

    final static String CLASS_NAME = MyJobListener.class.getName();

    @Override
    public String getName() {
        return CLASS_NAME;
    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void jobToBeExecuted(JobExecutionContext arg0) {
        try {
            SchedulerContext context = arg0.getScheduler().getContext();
            context.put(arg0.getJobDetail().getFullName(), false);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void jobWasExecuted(JobExecutionContext arg0,
            JobExecutionException arg1) {
		//Here you can again check for schedular context and take next course of action
		//e.g some database/file level logging, next job trigger
    }

}

You can see that MyJobListener class is implementing JobListener interface and methods jobToBeExecuted and jobWasExecuted are implemented. These method will give user full control to listen to the jobs status.