Quartz

Quartz Scheduler Properties Example

In this is article, we will see how to configure Quartz Scheduler using properties file. The properties file will be used by the scheduler factory to instantiate a scheduler.

The properties file can be used to inject the actual concrete classes of  the specified classes for example the JobStore, ThreadPool, and other SPI classes etc.

Before we start with the example, I will brief you about the quartz and the setup involved.

1. What is Quartz?

Quartz is a Java open source job-scheduling system capable of scheduling and executing jobs. In this example, we use the latest stable Quartz available which is version 2.2.1. You can download Quartz from http://quartz-scheduler.org/downloads

2. Quartz Setup

In this example, we will use Maven as the build tool so all you need to do is add the below dependency to pom.xml which looks like below.

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodegeeks.camel</groupId>
	<artifactId>camelHelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.1</version>
		</dependency>
	</dependencies>
</project>

3. Why do we need quartz.properties file?

The properties file can be used to inject the actual concrete classes of  the specified classes for example the JobStore, ThreadPool, and other SPI classes etc. Once the instance is created, its own properties will be set using the additional properties specified for them in the config file which will be used to invoke the corresponding setter method. For example if the properties file contains the property ‘org.quartz.jobStore.myProp = 10’ then after the JobStore class has been instantiated, the method ‘setMyProp()’ will be called on it. Type conversion to primitive Java types (int, long, float, double, boolean, and String) are performed before calling the property’s setter method.

4. Where is quartz.properties located?

One can specify the properties in the default file called “quartz.properties” which is assumed to be located current working directory. If it is not found there then “quartz.properties” file be searched in the org/quartz package. If you wish to use a file other than the default one, you must define the system property ‘org.quartz.properties’ to point to the file you want.

5. Referring to other properties

One property can reference another property’s value by specifying a value following the convention of “$@other.property.name”, for example, to reference the scheduler’s instance name as the value for some other property, you would use “$@org.quartz.scheduler.instanceName”.

6. Sample quartz.properties file

So how does a quartz.properties file look like. Here is a sample properties file.

org.quartz.scheduler.instanceName=JavacodeGeeksScheduler
org.quartz.scheduler.instanceId=99199
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=3
org.quartz.context.key.QuartzTopic=QuartzPorperties

7. Some of the main Quartz Properties

Let’s go through each available property.

  1. org.quartz.scheduler.instanceName – You can specify any value you want, scheduler won’t do any kind of validation. It is used for the client code to distinguish schedulers when it relies on multiple schedulers withing the same program. This is of great help, if you are using the clustering features and you want to rely on a logical scheduler.
  2. org.quartz.scheduler.instanceId – This maintains the uniqueness for all schedulers working within a cluster. The ID can be any value. There are couple of IDs which are special to the scheduler. They are the value AUTO and SYS_PROP. If it is AUTO quartz will automatically generate an ID for you. If it SYS_PROP, it means it is a system property and the value comes from the system property org.quartz.scheduler.instanceId.
  3. org.quartz.scheduler.instanceIdGenerator.class – This is used only if org.quartz.scheduler.instanceId is set to AUTO. By default, quartz generates the ID for you using its internal generator class org.quartz.simpl.SimpleInstanceIdGenerator. If you want to use a different generator, then the class name should be mentioned here. Quartz provide few more generator classes, you can write onf of your own by implementing InstanceIdGenerator.
  4. org.quartz.scheduler.threadName – This represents name of the Quartz java thread. If this property is not specified, the thread will derive its name from the scheduler’s name.
  5. org.quartz.scheduler.makeSchedulerThreadDaemon – This is a boolean value true or false that specifies whether the main thread of the scheduler should be a daemon thread or not.
  6. org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer – This is a boolean value true or false that specifies whether the threads spawned by Quartz will inherit the context ClassLoader of the initializing thread.
  7. org.quartz.scheduler.idleWaitTime – This is the wait time in milliseconds that the scheduler will use to wait before it starts to re-query for an available trigger when the scheduler is otherwise idle.
  8. org.quartz.scheduler.dbFailureRetryInterval – This will be used by the scheduler when it has lost the connection to JobStore database. This is the wait time of the scheduler before it tries re-connecting to the JobStore.
  9. org.quartz.scheduler.classLoadHelper.class – This is the helper class that Quartz uses to load a class or resource. By default it uses org.quartz.simpl.CascadingClassLoadHelper which in turn uses every other ClassLoadHelper class until one works.
  10. org.quartz.scheduler.jobFactory.class – The is class name of the JobFactory to use which is responsible for producing instances of Job Classes.
  11. org.quartz.context.key.SOME_KEY – It represent a name-value pair that will be placed into the “scheduler context” as strings. For example, org.quartz.context.key.QuartzTopic = QuartzProperties.
  12. org.quartz.scheduler.userTransactionURL – This is the JNDI URL at which Quartz can locate the Application Server’s UserTransaction manager, the default value is java:comp/UserTransaction
  13. org.quartz.scheduler.wrapJobExecutionInUserTransaction – Should be set to true if you want your job to be executed within a a UserTransaction.
  14. org.quartz.scheduler.skipUpdateCheck – This is used to log extra information in log in case an updated version of Quartz is available for download. It will decide Whether or not to skip running a quick web request to determine if there is an updated version of Quartz available for download./li>
  15. org.quartz.scheduler.batchTriggerAcquisitionMaxCount – The maximum number of triggers that a scheduler node is allowed to acquire (for firing) at once. Default value is 1.
  16. org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow – The amount of time in milliseconds that a trigger is allowed to be acquired and fired ahead of its scheduled fire time. Defaults to 0.

8. ThreadPool Properties

  1. org.quartz.threadPool.class – Name of the ThreadPool implementation that Quartz will use. In our example we will use org.quartz.simpl.SimpleThreadPool.
  2. org.quartz.threadPool.threadCount – Number of threads available for concurrent execution of jobs. This is be any positive integer, ideally between 1 and 100.
  3. org.quartz.threadPool.threadPriority – This can be any int between Thread.MIN_PRIORITY (which is 1) and Thread.MAX_PRIORITY (which is 10). The default is Thread.NORM_PRIORITY (5).

One can further specify properties based on the thread pool class chosen to set the thread pools’s properties.

9. Trigger Listener Properties

We can also configure trigger and job listeners through the configuration file consists of a property where we will specify the listener class name, and any other properties to be set on the instance. The class must have a no-arg constructor, and the properties are set reflectively.

  1. org.quartz.triggerListener.NAME.class – Trigger listener class name, should implement TriggerListener
  2. org.quartz.triggerListener.NAME.propName – Trigger listener’s property key and vale. There should be corresponding setter method.

10. Job Listener Properties

Just like trigger listener properties, we also have properties for job listener.

  1. org.quartz.jobListener.NAME.class – Job listener class name, should implement JobListener
  2. org.quartz.jobListener.NAME.propName – Job listener’s property key and vale. There should be corresponding setter method.

11. Example of Quartz Scheduler Properties

Let’s now combine some of the properties that we went through into an example.

Create your own Trigger listener.

MyTriggerListener:

package com.javacodegeeks.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;

public class MyTriggerListener implements TriggerListener {
	private String someProp;

	public String getName() {
		return "MyTrigger: " + someProp;
	}

	public void triggerFired(Trigger trigger, JobExecutionContext context) {
		System.out.println("Trigger fired: " + trigger.getDescription());
	}

	public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
		return false;
	}

	public void triggerMisfired(Trigger trigger) {
	}

	public void triggerComplete(Trigger trigger, JobExecutionContext context,
			CompletedExecutionInstruction triggerInstructionCode) {
		System.out.println("Trigger completed: " + trigger.getDescription());
	}

	public String getSomeProp() {
		return someProp;
	}

	public void setSomeProp(String someProp) {
		this.someProp = someProp;
	}	
}

and a job listener.

MyJobListener:

package com.javacodegeeks.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;

public class MyJobListener implements JobListener {
	
	private String someProp;		

	public String getSomeProp() {
		return someProp;
	}

	public void setSomeProp(String someProp) {
		this.someProp = someProp;
	}

	public String getName() {
		return "MyJobListener: " + someProp;
	}

	public void jobToBeExecuted(JobExecutionContext context) {
		System.out.println("Job to be exected: " + context.getFireInstanceId() + ", job listener: " + getName());
	}

	public void jobExecutionVetoed(JobExecutionContext context) {
	}

	public void jobWasExecuted(JobExecutionContext context,
			JobExecutionException jobException) {
		System.out.println("Job was exected: " + context.getFireInstanceId() + ", job listener: " + getName());
	}

}

Let’s now define our job

MyJob:

package com.javacodegeeks.quartz;

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

public class MyJob implements Job {
	private static int count;

	public void execute(JobExecutionContext jobContext) throws JobExecutionException {
		System.out.println("--------------------------------------------------------------------");
		System.out.println("MyJob start: " + jobContext.getFireTime());
		JobDetail jobDetail = jobContext.getJobDetail();
		System.out.println("Example name is: " + jobDetail.getJobDataMap().getString("example"));		
		System.out.println("MyJob end: " + jobContext.getJobRunTime() + ", key: " + jobDetail.getKey());
		System.out.println("MyJob next scheduled time: " + jobContext.getNextFireTime());
		System.out.println("--------------------------------------------------------------------");
		System.out.println("Job's thread name is: " + Thread.currentThread().getName());
		ILatch latch = (ILatch) jobDetail.getJobDataMap().get("latch");
		latch.countDown();
		count++;
		System.out.println("Job count " + count);
		if (count == 2) {
			throw new RuntimeException("Some RuntimeException!");
		}
		if (count == 4) {
			throw new JobExecutionException("Some JobExecutionException!");
		}
	}

}

We want to make sure that the scheduler shuts down automatically after a specified runs so we have a latch which we count down as and when a job is run.

ILatch:

package com.javacodegeeks.quartz;

public interface ILatch {
	void countDown();
}

Here is our main example.

QuartzSchedulerPropertiesExample:

package com.javacodegeeks.quartz;

import java.util.concurrent.CountDownLatch;

import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
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.TriggerBuilder;


public class QuartzSchedulerPropertiesExample implements ILatch {
	private int repeatCount = 3;
	private CountDownLatch latch = new CountDownLatch(repeatCount + 1);
	public static void main(String[] args) throws Exception {	
		QuartzSchedulerPropertiesExample quartzSchedulerExample = new QuartzSchedulerPropertiesExample();
		quartzSchedulerExample.fireJob();
	}
	
	public void fireJob() throws SchedulerException, InterruptedException {
		SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
		Scheduler scheduler = schedFact.getScheduler();
		System.out.println("Scheduler name is: " + scheduler.getSchedulerName());
		System.out.println("Scheduler instance ID is: " + scheduler.getSchedulerInstanceId());	
		System.out.println("Scheduler context's value for key QuartzTopic is " + scheduler.getContext().getString("QuartzTopic"));
		scheduler.start();
		
		// define the job and tie it to our HelloJob class
		JobBuilder jobBuilder = JobBuilder.newJob(MyJob.class);
		JobDataMap data = new JobDataMap();
		data.put("latch", this);
		
		JobDetail jobDetail = jobBuilder.usingJobData("example", "com.javacodegeeks.quartz.QuartzSchedulerExample")	
				.usingJobData(data)
				.withIdentity("myJob", "group1")
				.build();
		
		
		// Trigger the job to run now, and then every 40 seconds
		Trigger trigger = TriggerBuilder.newTrigger()
		.withIdentity("myTrigger", "group1")
		.startNow()
		.withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withRepeatCount(repeatCount)
                .withIntervalInSeconds(2))	
                .withDescription("MyTrigger")
		.build();
			
		// Tell quartz to schedule the job using our trigger
		scheduler.scheduleJob(jobDetail, trigger);
		latch.await();
		System.out.println("All triggers executed. Shutdown scheduler");
		scheduler.shutdown();
	}
	
	public void countDown() {
		latch.countDown();
	}
}

Here is our complete quartz properties file.

quartz.properties:

org.quartz.scheduler.instanceName=JavacodeGeeksScheduler
org.quartz.scheduler.instanceId=99199
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=3
org.quartz.context.key.QuartzTopic=QuartzPorperties
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
org.quartz.triggerListener.NAME.class=com.javacodegeeks.quartz.MyTriggerListener
org.quartz.triggerListener.NAME.someProp=SomeTriggerValue
org.quartz.jobListener.NAME.class= com.javacodegeeks.quartz.MyJobListener
org.quartz.jobListener.NAME.someProp=SomeJobValue

You can see from the output that the Quartz Scheduler was able to pick up the scheduler name, its instance ID, trigger listener, job listener, the key value properties of the scheduler context as well as the other listener properties.

Output:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Scheduler name is: JavacodeGeeksScheduler
Scheduler instance ID is: 99199
Scheduler context's value for key QuartzTopic is QuartzPorperties
Trigger fired: MyTrigger
Job to be exected: 1443678721202, job listener: MyJobListener: SomeJobValue
--------------------------------------------------------------------
MyJob start: Thu Oct 01 11:22:01 IST 2015
Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample
MyJob end: -1, key: group1.myJob
MyJob next scheduled time: Thu Oct 01 11:22:03 IST 2015
--------------------------------------------------------------------
Job's thread name is: JavacodeGeeksScheduler_Worker-1
Job count 1
Job was exected: 1443678721202, job listener: MyJobListener: SomeJobValue
Trigger completed: MyTrigger
Trigger fired: MyTrigger
Job to be exected: 1443678721203, job listener: MyJobListener: SomeJobValue
--------------------------------------------------------------------
MyJob start: Thu Oct 01 11:22:03 IST 2015
Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample
MyJob end: -1, key: group1.myJob
MyJob next scheduled time: Thu Oct 01 11:22:05 IST 2015
--------------------------------------------------------------------
Job's thread name is: JavacodeGeeksScheduler_Worker-2
Job count 2
Job was exected: 1443678721203, job listener: MyJobListener: SomeJobValue
Trigger completed: MyTrigger
Trigger fired: MyTrigger
Job to be exected: 1443678721204, job listener: MyJobListener: SomeJobValue
--------------------------------------------------------------------
MyJob start: Thu Oct 01 11:22:05 IST 2015
Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample
MyJob end: -1, key: group1.myJob
MyJob next scheduled time: Thu Oct 01 11:22:07 IST 2015
--------------------------------------------------------------------
Job's thread name is: JavacodeGeeksScheduler_Worker-3
Job count 3
Job was exected: 1443678721204, job listener: MyJobListener: SomeJobValue
Trigger completed: MyTrigger
Trigger fired: MyTrigger
Job to be exected: 1443678721205, job listener: MyJobListener: SomeJobValue
--------------------------------------------------------------------
MyJob start: Thu Oct 01 11:22:07 IST 2015
Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample
MyJob end: -1, key: group1.myJob
MyJob next scheduled time: null
--------------------------------------------------------------------
Job's thread name is: JavacodeGeeksScheduler_Worker-1
Job count 4
All triggers executed. Shutdown scheduler
Job was exected: 1443678721205, job listener: MyJobListener: SomeJobValue
Trigger completed: MyTrigger

12. Download the Eclipse Project

This was an example about Quartz Scheduler Properties.

Download
You can download the full source code of this example here: quartzSchedulerPropertiesExample.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Sunny
Sunny
4 years ago

I am thinking a seperate quartz.properties is needed, if you are extensively using Quartz and with a separate quartz activities persistence database instead of using application database. e.g. for Mysql schemas it can be: application database schema – MyAppDb quartz database schema – MyAppQuartzDB However, it is not mentioned how to make Quartz look for quartz.properties file. Is it a config in application.properties? Or Is it the usual @Configuration annotated class route with the @Bean annotated method: e.g. @Bean public SchedulerFactoryBean configureQuartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setConfigLocation(new ClassPathResource(“/quartz.properties”)); return schedulerFactoryBean; } Also, in case of a Spring Boot… Read more »

Back to top button