Quartz schedular framework can be used to schedule jobs. This post explains how we can use it with a simple example.
We need the below jars
1) c3p0-0.9.1.1.jar
2) log4j-1.2.16.jar
3) quartz-2.2.3.jar
4) quartz-jobs-2.2.3.jar
5) slf4j-api-1.7.7.jar
6) slf4j-log4j12-1.7.7.jar
log4j.xml file in the classpath with the below configurations
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="default" class="org.apache.log4j.ConsoleAppender">
<param name="target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%p] %d{dd MMM hh:mm:ss.SSS aa} %t [%c]%n%m%n%n"/>
</layout>
</appender>
<logger name="org.quartz">
<level value="info" />
</logger>
<root>
<level value="info" />
<appender-ref ref="default" />
</root>
</log4j:configuration>
To schedule a job we need an instance of Scheduler, which can be obtained as shown below
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler schedular = schedulerFactory.getScheduler();
In the above snippet, we create an instance of StdSchedulerFactory provided by Quartz framework and assigned to SchedulerFactory interface.
From the interface we create an instance of Scheduler class by calling getScheduler method.
Next we have to create the job which will be scheduled to be executed by implementing the Job interface as shown below
Job Code
package package1;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Hello Job is executing.");
}
}
As shown in the above code, we create a job class named HelloJob implementing the interface Job.
Next we create a JobDetail. An instance of JobDetail is used define instance of job and to provide job parameters and configuration information that will be passed to a particular instance of job, which will be accessible via JobExecutionContext as shown below
JobBuilder jobBuilder = JobBuilder.newJob(HelloJob.class);
jobBuilder.withDescription("Job Description").withIdentity("jobDetail1", "group1");
JobDetail jobDetail = jobBuilder.build();
We take the help of utility class named JobBuilder to create an instance of JobDetail with required parameters and configuration information.
In the above code snippet we create an instance of JobDetail. We give an identity “jobDetail1” to the instance of JobDetail, associate it to a group named “group1”, and provide description for other developers to understand the purpose of creating the job detail.
Job interface is used to define the task to be done.
JobDetail class is used to define instance of job and the parameters and configurations that will be passed to a particular instance of job.
Both class helps in separating “what to be done” from “On what to be done”.
Next we create a schedule for the job instance as shown below
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatSecondlyForTotalCount(10);
In the above code snippet we have created a schedule, the schedule is to repeat the JobDetail identified by “jobDetail1” to be run every second for total of 10 times.
Next we build a trigger that will follow the schedule and trigger the job, as shown below
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder.withSchedule(simpleScheduleBuilder).withDescription("Trigger Description").withIdentity("trigger1", "group1").startNow();
Trigger trigger = triggerBuilder.build();
In the above code snippet, we create a trigger give it an identity and assign it to a group. We assign the schedule, that we want the job to follow, which is in this case is simpleScheduleBuilder that we created earlier.
Now we provide both the JobDetail and trigger to the schedular as shown below
schedular.scheduleJob(jobDetail, trigger);
Next we start schedular as shown below
schedular.start();
Once started, we can get the status of the schedule with the help of TriggerState, as shown below
TriggerState triggerState = schedular.getTriggerState(trigger.getKey());
while(triggerState != TriggerState.NONE) {
triggerState = schedular.getTriggerState(trigger.getKey());
}
This code will run the loop untill the state changes to NONE.
As long as TriggerState is not in NONE, means the scheduler is in one of the following states
- BLOCKED
- COMPLETE
- ERROR
- NORMAL
- PAUSED
Next we shutdown the schedular as shown below
schedular.shutdown(true);
We pass boolean true as a parameter indicating the schedular to wait for the running jobs to complete.
Below is complete code
Main code
package package1;
import java.io.IOException;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzDemo1 {
public static void main(String[] args) throws SchedulerException, IOException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler schedular = schedulerFactory.getScheduler();
JobBuilder jobBuilder = JobBuilder.newJob(HelloJob.class);
jobBuilder.withDescription("Job Description").withIdentity("jobDetail1", "group1");
JobDetail jobDetail = jobBuilder.build();
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatSecondlyForTotalCount(10);
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder.withSchedule(simpleScheduleBuilder).withDescription("Trigger Description").withIdentity("trigger1", "group1").startNow();
Trigger trigger = triggerBuilder.build();
schedular.scheduleJob(jobDetail, trigger);
schedular.start();
TriggerState triggerState = schedular.getTriggerState(trigger.getKey());
while(triggerState != TriggerState.NONE) {
triggerState = schedular.getTriggerState(trigger.getKey());
}
schedular.shutdown(true);
}
}
Output
[INFO] 18 Mar 12:32:24.427 PM main [org.quartz.impl.StdSchedulerFactory]
Using default implementation for ThreadExecutor
[INFO] 18 Mar 12:32:24.427 PM main [org.quartz.simpl.SimpleThreadPool]
Job execution threads will use class loader of thread: main
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.core.SchedulerSignalerImpl]
Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.core.QuartzScheduler]
Quartz Scheduler v.2.2.3 created.
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.simpl.RAMJobStore]
RAMJobStore initialized.
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.core.QuartzScheduler]
Scheduler meta-data: Quartz Scheduler (v2.2.3) ‘DefaultQuartzScheduler’ 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 10 threads.
Using job-store ‘org.quartz.simpl.RAMJobStore’ – which does not support persistence. and is not clustered.
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler ‘DefaultQuartzScheduler’ initialized from default resource file in Quartz package: ‘quartz.properties’
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler version: 2.2.3
[INFO] 18 Mar 12:32:24.442 PM main [org.quartz.core.QuartzScheduler]
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
Hello Job is executing.
[INFO] 18 Mar 12:32:33.443 PM main [org.quartz.core.QuartzScheduler]
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[INFO] 18 Mar 12:32:33.443 PM main [org.quartz.core.QuartzScheduler]
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[INFO] 18 Mar 12:32:33.950 PM main [org.quartz.core.QuartzScheduler]
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.