In this post, we will discuss the java job scheduler called “Quartz”. In a brief introduction, quartz is providing job scheduling infrastructure to integrate with standalone applications to large enterprise applications, to perform the defined tasks on scheduling basis.
The use case to use Quartz is any task which is performing on a regular interval of time. For example, in an e-commerce application, if you have a job to process the inventory feed on a daily basis, then we can create a Quartz job to trigger the task.
Quartz can be integrated as part of any standalone application, any servlet container, via RMI or as a cluster of stand-alone programs (with load-balance and fail-over capabilities). We can create persistence jobs or in-memory jobs.
Now, we will see how we can create a simple job to send emails to all users on a daily basis. Before that, we will see how to set up a development environment to use Quartz.
-
As a first step, download the most recent stable release from http://www.quartz-scheduler.org/downloads/ . In this example, I am using Quartz 2.1.7.
-
After downloading, unpack the zip file. The unpacked Quartz package contains a number of jar files, located under the root directory. The main Quartz library is named quartz-all-2.1.7.jar. This jar includes all the Quartz features.
-
Keep the quartz-all-2.1.7.jar into our application classpath.
-
Keep all the dependent jar files (slf4j-log4j12-1.6.1.jar,slf4j-api-1.6.1.jar,log4j-1.2.16.jar,javax.transaction.jar,c3p0-0.9.1.1.jar) into the class path.
- Keep quartz.properties file in class path.
All the configuration details will be available under quartz.properties file. So, the Quartz scheduler will take the configuration details from here.
Now, we will create a standalone Java application to demonstrate the Quartz. The source code is available here https://github.com/2013techsmarts/Quartz_Proj
The sample code creates a scheduler instance is given below.
package com.smarttechies.scheduler; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory; public class MailScheduler { /** * @param args */ public static void main(String[] args) { try { SchedulerFactory sf = new StdSchedulerFactory(); Scheduler scheduler = sf.getScheduler(); scheduler.start(); } catch (SchedulerException se) { se.printStackTrace(); } } }
We are getting scheduler instance by calling org.quartz.impl.StdSchedulerFactory.getDefaultScheduler method. We are starting the scheduler by calling the start method. When we start the scheduler, it will get the configuration from the quartz.properties available in the classpath.
The log will depict some of the scheduler details.
2013-04-19 22:18:42 INFO StdSchedulerFactory:1175 - Using default implementation for ThreadExecutor 2013-04-19 22:18:42 INFO SchedulerSignalerImpl:61 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2013-04-19 22:18:42 INFO QuartzScheduler:243 - Quartz Scheduler v.2.1.7 created. 2013-04-19 22:18:42 INFO RAMJobStore:154 - <strong>RAMJobStore</strong> initialized. 2013-04-19 22:18:42 INFO QuartzScheduler:268 - Scheduler meta-data: Quartz Scheduler (v2.1.7) '<strong>MailScheduler</strong>' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads. Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. 2013-04-19 22:18:42 INFO StdSchedulerFactory:1324 - Quartz scheduler 'MailScheduler' initialized from default file in current working dir: 'quartz.properties' 2013-04-19 22:18:42 INFO StdSchedulerFactory:1328 - Quartz scheduler version: 2.1.7 2013-04-19 22:18:42 INFO QuartzScheduler:534 - Scheduler MailScheduler_$_NON_CLUSTERED started.
From the log, we can understand that scheduler is using quartz.properties and we have configured in-memory scheduler. So, it is using RAM job store.
Now, we create a job and trigger to run the job every minute. To create a job, we need to implement org.quartz.Job interface and provide implementation to the execute method.
The sample MailSenderJob code is given below.
package com.smarttechies.job; import org.apache.log4j.Logger; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class MailSenderJob implements Job{ Logger log = Logger.getLogger(MailSenderJob.class); @Override public void execute(JobExecutionContext pArg0) throws JobExecutionException { log.info("The mail sender job triggerd"); //From here call the mail sender service } }
Now, in the MailScheduler code which was written earlier, we need to configure the job and the trigger. After the change, the MailScheduler code will be as shown below.
package com.smarttechies.scheduler; import java.text.ParseException; import org.quartz.CronExpression; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.impl.JobDetailImpl; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.triggers.CronTriggerImpl; import com.smarttechies.job.MailSenderJob; public class MailScheduler { /** * @param args * @throws ParseException */ public static void main(String[] args) throws ParseException { try { SchedulerFactory sf = new StdSchedulerFactory(); Scheduler scheduler = sf.getScheduler(); //Tie the MailSenderJob to scheduler JobDetailImpl jobDetail = new JobDetailImpl(); jobDetail.setGroup("group1"); JobKey jobKey = new JobKey("job1"); jobDetail.setKey(jobKey); jobDetail.setJobClass(MailSenderJob.class); //create a trigger and tie it to the job // Trigger the job to run on every minute CronExpression cronExpression = new CronExpression("0 0/1 * 1/1 * ? *"); CronTriggerImpl cronTrigger = new CronTriggerImpl(); cronTrigger.setName("mail trigger"); cronTrigger.setCronExpression(cronExpression); //Tie the job and the trigger to the scheduler scheduler.scheduleJob(jobDetail, cronTrigger); scheduler.start(); } catch (SchedulerException se) { se.printStackTrace(); } } }
The above scheduler will trigger the job every minute. The log indicates the same.
2013-04-20 11:26:11 INFO StdSchedulerFactory:1175 - Using default implementation for ThreadExecutor 2013-04-20 11:26:11 INFO SchedulerSignalerImpl:61 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2013-04-20 11:26:11 INFO QuartzScheduler:243 - Quartz Scheduler v.2.1.7 created. 2013-04-20 11:26:11 INFO RAMJobStore:154 - RAMJobStore initialized. 2013-04-20 11:26:11 INFO QuartzScheduler:268 - Scheduler meta-data: Quartz Scheduler (v2.1.7) 'MailScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads. Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. 2013-04-20 11:26:11 INFO StdSchedulerFactory:1324 - Quartz scheduler 'MailScheduler' initialized from default file in current working dir: 'quartz.properties' 2013-04-20 11:26:11 INFO StdSchedulerFactory:1328 - Quartz scheduler version: 2.1.7 2013-04-20 11:26:11 INFO QuartzScheduler:534 - Scheduler MailScheduler_$_NON_CLUSTERED started. 2013-04-20 11:27:00 INFO <strong>MailSenderJob:14 - The mail sender job triggerd</strong>
To stop the scheduler, we need to call the shutDown method on the scheduler.
The approach we followed in this article to configure the job and trigger is programmatic. In the coming post, we will see, how we can improve the same code by moving the job and trigger configurations to an XML file by using quartz plugins.
Leave a Reply