Objective of this to create Scheduler as
1. REST service.
2. Persist scheduler data to a database
Here i use spring boot , quartz, mysql
Below is the link to sql script to create necessary table structure
https://cgenit.blogspot.com/2019/02/quartz-sql-script.html
Use Spring Initializer to create the project
https://start.spring.io/
Below is the POM file
https://cgenit.blogspot.com/2019/02/create-quartz-scheduler-as-rest-service_13.html
Few Annotations to be noted:
1. @EnableScheduling - use in Springboot main class along with @SpringBootApplication
2. @PersistJobDataAfterExecution - used in Quartz job class eg: SyncJob
Below is the code for the Service
1. Controller class - with few selected service calls
package com.com.saap.scheduler.controller;
import java.util.List;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.com.saap.scheduler.model.SaapJob;
import com.com.saap.scheduler.model.SaapJob1;
import com.com.saap.scheduler.model.SaapJobKey;
import com.com.saap.scheduler.model.SaapTrigger;
import com.com.saap.scheduler.service.SchedulerService;
@RestController
@RequestMapping("sheduler")
public class ShedulerController {
@Autowired
SchedulerService schedulerService;
/**
* Returns list of schedule jobs.
*
* @return List
list of jobs.
* @throws SchedulerException
*/
@GetMapping("/jobs")
public ResponseEntity
> getJobList() throws SchedulerException {
List
jobList = schedulerService.getJobList();
return new ResponseEntity
>(jobList, HttpStatus.OK);
}
/**
* Filter list of jobs with give state.
*
* @param state state of the job.
* @return list of jobs.
* @throws SchedulerException
*/
@GetMapping("/jobs/{state}")
public ResponseEntity
> getJobList(@PathVariable("state") String state) throws SchedulerException {
List
jobList = schedulerService.getJobList(state);
return new ResponseEntity
>(jobList, HttpStatus.OK);
}
/**
* Schedule a job. A new Trigger will be created and will be assign to same job.
*
* @param jobDetail {@link SaapJob} Information needs to create and schedule a
* job.
* @return
* @throws ClassNotFoundException
* @throws SchedulerException
*/
@PostMapping("job")
public ResponseEntity
createSheduler(@RequestBody SaapJob1 jobDetail)
throws ClassNotFoundException, SchedulerException {
// pass the full object
schedulerService.sheduleJob(jobDetail.getJobClass(), jobDetail.getJobName(), jobDetail.getJobGroup(),
jobDetail.getTriggerName(), jobDetail.getTriggerGroup(), jobDetail.getCronExpression(),
jobDetail.getSourceURL(), jobDetail.getDestinationURL());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
* Delete a job with given {@link SaapJobKey}.
*
* @param jobkey combination of job name and corresponding group.
* @return
* @throws SchedulerException
*/
@PostMapping("job/del")
public ResponseEntity
deleteJob(@RequestBody SaapJobKey jobkey) throws SchedulerException {
schedulerService.deleteJob(jobkey.getJobName(), jobkey.getJobGroup());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
* Pause a job with given {@link SaapJobKey}.
*
* @param jobkey combination of job name and corresponding group.
* @return
* @throws SchedulerException
*/
@PostMapping("job/pause")
public ResponseEntity
pauseJob(@RequestBody SaapJobKey jobkey) throws SchedulerException {
schedulerService.pauseJob(jobkey.getJobName(), jobkey.getJobGroup());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
* Resume a job with given {@link SaapJobKey}.
*
* @param jobkey combination of job name and corresponding group.
* @return
* @throws SchedulerException
*/
@PostMapping("job/resume")
public ResponseEntity
resumeJob(@RequestBody SaapJobKey jobkey) throws SchedulerException {
schedulerService.resumeJob(jobkey.getJobName(), jobkey.getJobGroup());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
* Interrupt a job with given {@link SaapJobKey}.
*
* @param jobkey combination of job name and corresponding group.
* @return
* @throws SchedulerException
*/
@PostMapping("job/interrupt")
public ResponseEntity
interruptJob(@RequestBody SaapJobKey jobkey) throws SchedulerException {
schedulerService.interruptJob(jobkey.getJobName(), jobkey.getJobGroup());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
* Trigger a job with given {@link SaapJobKey}.
*
* @param jobkey combination of job name and corresponding group.
* @return
* @throws SchedulerException
*/
@PostMapping("job/trigger")
public ResponseEntity
triggerJob(@RequestBody SaapJobKey jobkey) throws SchedulerException {
// TODO Auto-generated method stub
schedulerService.triggerJob(jobkey.getJobName(), jobkey.getJobGroup());
return null;
}
/**
* Change Cron expression of a trigger.
*
* @param triggerDetail Trigger details.
* @return
* @throws SchedulerException
*/
@PutMapping("job/trigger")
public ResponseEntity
changeTrigger(@RequestBody SaapTrigger triggerDetail) throws SchedulerException {
schedulerService.changeTriggerForJob(triggerDetail.getTriggerKey().getName(),
triggerDetail.getTriggerKey().getGroup(), triggerDetail.getCronExpression());
HttpHeaders headers = new HttpHeaders();
return new ResponseEntity
(headers, HttpStatus.OK);
}
/**
*
* @return
* @throws SchedulerException
*/
@GetMapping("start")
public ResponseEntity
start() throws SchedulerException {
schedulerService.start();
return new ResponseEntity
(HttpStatus.OK);
}
/**
*
* @return
* @throws SchedulerException
*/
@GetMapping("shutdown")
public ResponseEntity
shutdown() throws SchedulerException {
schedulerService.shutdown();
return new ResponseEntity
(HttpStatus.OK);
}
}
2. Singleton class to create Scheduler object - not used as we use Spring bean
package com.com.saap.scheduler.core;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
public class SaapScheduler {
private static volatile Scheduler scheduler = null;
// make this singleton
public Scheduler getScheduler() throws SchedulerException {
if (scheduler == null) {
scheduler = new StdSchedulerFactory().getScheduler();
}
return scheduler;
}
public void start(Scheduler scheduler) throws SchedulerException {
if (scheduler != null) {
scheduler.start();
}
}
public void shutDown(Scheduler scheduler) throws SchedulerException {
if (scheduler != null) {
scheduler.shutdown();
}
}
}
3. Sample Job classes
3. 1 HelloJob.java -- simple job to print a line
package com.com.saap.scheduler.job;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println(new Date() + "Hello Quartz!");
}
}
3.2 SyncJob.java --> do a Sync job. take data from one REST API call and POST to anther REST API
Note : @PersistJobDataAfterExecution
package com.com.saap.scheduler.job;
import java.util.Date;
import java.util.logging.Logger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
@PersistJobDataAfterExecution
public class SyncJob implements Job {
private static Logger LOG = Logger.getLogger(SyncJob.class.getName());
public static final String SOURCE_URL = "sourceURL";
public static final String DESTINATION_URL = "destinationURL";
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println(new Date() + "SyncJob Quartz!");
JobKey jobKey = context.getJobDetail().getKey();
// Grab and print passed parameters
JobDataMap data = context.getJobDetail().getJobDataMap();
String sourceURL = data.getString(SOURCE_URL);
String destinationURL = data.getString(DESTINATION_URL);
LOG.info("************ stat start SyncJob ***************");
LOG.info("jobKey.getName() =" + jobKey.getName());
LOG.info("sourceURL =" + sourceURL);
LOG.info("destinationURL=" + destinationURL);
LOG.info("************ stat end SyncJob ***************");
/**
* Implementing Job Here
*
*/
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
RestTemplate restTemplate = new RestTemplate();
String url = data.getString(SOURCE_URL);
HttpEntity
requestEntity = new HttpEntity(headers);
try {
ResponseEntity
responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
SyncJobResponse.class, 1);
LOG.info(responseEntity.toString());
} catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
}
}
}
4. Model classes use to transfer data
4.1 SaapJob.java
package com.com.saap.scheduler.model;
import java.io.Serializable;
/**
* Combination of the job functionality and the Trigger details relates to job.
*
*
*/
public class SaapJob implements Serializable {
/**
*
*/
private static final long serialVersionUID = 688729605535527366L;
/**
* Details of the job functionality..
*/
private SaapJobDetail jobDetail;
/**
* Details of the Trigger.
*/
private SaapTrigger trigger;
public SaapJob(SaapJobDetail jobDetail, SaapTrigger trigger) {
this.jobDetail = jobDetail;
this.trigger = trigger;
}
public SaapJob() {
}
public SaapJobDetail getJobDetail() {
return jobDetail;
}
public void setJobDetail(SaapJobDetail jobDetail) {
this.jobDetail = jobDetail;
}
public SaapTrigger getTrigger() {
return trigger;
}
public void setTrigger(SaapTrigger trigger) {
this.trigger = trigger;
}
}
4.2 SaapJob1.java - old class with all data
package com.com.saap.scheduler.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class SaapJob1 implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2734719600011908418L;
private String jobClass;
private String jobName;
private String jobGroup;
private String triggerName;
private String triggerGroup;
private String cronExpression;
private String triggerState;
Date nextFireTime;
///
private String sourceURL;
private String destinationURL;
List jobDataList = new ArrayList();
public SaapJob1() {
}
public SaapJob1(String jobClass, String jobName, String jobGroup, String triggerName, String triggerGroup,
String cronExpression, Date nextFireTime, String triggerState) {
this.jobClass = jobClass;
this.jobName = jobName;
this.jobGroup = jobGroup;
this.triggerName = triggerName;
this.triggerGroup = triggerGroup;
this.cronExpression = cronExpression;
this.nextFireTime = nextFireTime != null ? (Date) nextFireTime.clone() : null;
this.triggerState = triggerState;
}
public String getJobClass() {
return jobClass;
}
public void setJobClass(String jobClass) {
this.jobClass = jobClass;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String getTriggerGroup() {
return triggerGroup;
}
public void setTriggerGroup(String triggerGroup) {
this.triggerGroup = triggerGroup;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getTriggerState() {
return triggerState;
}
public void setTriggerState(String triggerState) {
this.triggerState = triggerState;
}
public Date getNextFireTime() {
return nextFireTime != null ? (Date) nextFireTime.clone() : null;
}
public void setNextFireTime(Date nextFireTime) {
this.nextFireTime = nextFireTime != null ? (Date) nextFireTime.clone() : null;
}
public String getSourceURL() {
return sourceURL;
}
public void setSourceURL(String sourceURL) {
this.sourceURL = sourceURL;
}
public String getDestinationURL() {
return destinationURL;
}
public void setDestinationURL(String destinationURL) {
this.destinationURL = destinationURL;
}
public List getJobDataList() {
return jobDataList;
}
public void setJobDataList(List jobDataList) {
this.jobDataList = jobDataList;
}
}
4.3 SaapJobData
package com.com.saap.scheduler.model;
import java.io.Serializable;
public class SaapJobData implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6234077751506588604L;
private String key;
private String value;
public SaapJobData() {
}
SaapJobData(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
4.4 SaapJobDetail
package com.com.saap.scheduler.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Conveys the detail properties of a given SaapJob
instance.
*
*
* SaapobDetail
contains
*
jobClass
*
jobDescription
*
jobKey
*
jobDataList
*
*
*
*
*
*/
public class SaapJobDetail implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3059373659998965232L;
/**
* name of the job class which logic is encapsulated.
*/
private String jobClass;
/**
* Abstract description of the job.
*/
private String jobDescription;
/**
* Unique job name and job group combination to identify the job.
*/
private SaapJobKey jobKey;
/**
* List of {@link SaapJobData} which use as meta data for the job.
*/
List jobDataList = new ArrayList();
public SaapJobDetail() {
}
public SaapJobDetail(String jobClass, String jobDescription, SaapJobKey jobKey, List jobDataList) {
this.jobClass = jobClass;
this.jobDescription = jobDescription;
this.jobKey = jobKey;
this.jobDataList = jobDataList;
}
public String getJobClass() {
return jobClass;
}
public void setJobClass(String jobClass) {
this.jobClass = jobClass;
}
public String getJobDescription() {
return jobDescription;
}
public void setJobDescription(String jobDescription) {
this.jobDescription = jobDescription;
}
public SaapJobKey getJobKey() {
return jobKey;
}
public void setJobKey(SaapJobKey jobKey) {
this.jobKey = jobKey;
}
public List getJobDataList() {
return jobDataList;
}
public void setJobDataList(List jobDataList) {
this.jobDataList = jobDataList;
}
}
4.5 SaapJobKey
package com.com.saap.scheduler.model;
import java.io.Serializable;
/**
* Job is identified uniquely using jobkey comprise of name and group. The
* combination is unique.
*
*
*
*/
public class SaapJobKey implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5196501106111618671L;
/**
* Name for particular job.
*/
private String jobName;
/**
* Group name for particular job.
*/
private String jobGroup;
public SaapJobKey() {
}
public SaapJobKey(String jobName, String jobGroup) {
this.jobName = jobName;
this.jobGroup = jobGroup;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
}
4.6 SaapTrigger
package com.com.saap.scheduler.model;
import java.io.Serializable;
import java.util.Date;
import java.util.TimeZone;
import org.quartz.Scheduler;
import org.quartz.Trigger;
/**
*
* SaapTriggers
s have a {@link SaapTriggerKey} associated with
* them, which should uniquely identify them within a single
* {@link Scheduler}
.
*
*
*
* SaapTrigger
s are the 'mechanism' by which SaapJob
s
* are scheduled. Many SaapTrigger
s can point to the same
* SaapJob
, but a single SaapTrigger
can only point to
* one SaapJob
.
*
*
*
* SaapTriggers can 'send' parameters/data to SaapJob
s by placing
* contents into the List
on the
* SaapTrigger
.
*
*
*
*
*/
public class SaapTrigger implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4507610386211548655L;
private SaapTriggerKey triggerKey;
private String description;
private String cronExpression;
private int priority = Trigger.DEFAULT_PRIORITY;
private String triggerState;
private Date startTime = null;
private Date endTime = null;
private Date nextFireTime = null;
private Date previousFireTime = null;
private transient TimeZone timeZone = null;
public SaapTrigger() {
}
public SaapTrigger(SaapTriggerKey triggerKey, String description, String cronExpression, int priority) {
this.triggerKey = triggerKey;
this.description = description;
this.cronExpression = cronExpression;
this.priority = priority;
}
public SaapTriggerKey getTriggerKey() {
return triggerKey;
}
public void setTriggerKey(SaapTriggerKey triggerKey) {
this.triggerKey = triggerKey;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getTriggerState() {
return triggerState;
}
public void setTriggerState(String triggerState) {
this.triggerState = triggerState;
}
public Date getStartTime() {
return startTime != null ? (Date) startTime.clone() : null;
}
public void setStartTime(Date startTime) {
this.startTime = startTime != null ? (Date) startTime.clone() : null;
}
public Date getEndTime() {
return endTime != null ? (Date) endTime.clone() : null;
}
public void setEndTime(Date endTime) {
this.endTime = endTime != null ? (Date) endTime.clone() : null;
}
public Date getNextFireTime() {
return nextFireTime != null ? (Date) nextFireTime.clone() : null;
}
public void setNextFireTime(Date nextFireTime) {
this.nextFireTime = nextFireTime != null ? (Date) nextFireTime.clone() : null;
}
public Date getPreviousFireTime() {
return previousFireTime != null ? (Date) previousFireTime.clone() : null;
}
public void setPreviousFireTime(Date previousFireTime) {
this.previousFireTime = previousFireTime != null ? (Date) previousFireTime.clone() : null;
}
public TimeZone getTimeZone() {
return timeZone;
}
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
}
4.7 SaapTriggerKey
package com.com.saap.scheduler.model;
import java.io.Serializable;
/**
* Uniquely identifies a {@link SaapTriggerKey}.
*
*
* Keys are composed of both a name and group, and the name must be unique
* within the group. If only a name is specified then the default group name
* will be used.
*
*
*
*
*/
public class SaapTriggerKey implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2271019390246303775L;
/**
* The default group for scheduling entities, with the value "DEFAULT".
*/
public static final String DEFAULT_GROUP = "DEFAULT";
/**
* name of the Trigger.
*/
private String name;
/**
* group of the Trigger.
*/
private String group;
public SaapTriggerKey() {
}
public SaapTriggerKey(String name) {
this(name, null);
}
public SaapTriggerKey(String name, String group) {
if (name == null)
throw new IllegalArgumentException("Name cannot be null.");
this.name = name;
if (group != null)
this.group = group;
else
this.group = DEFAULT_GROUP;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
@Override
public String toString() {
return "SaapTriggerKey [name=" + name + ", group=" + group + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((group == null) ? 0 : group.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
equalsTriggerKey(obj);
return true;
}
private boolean equalsTriggerKey(Object obj) {
SaapTriggerKey other = (SaapTriggerKey) obj;
if (group == null) {
if (other.group != null)
return false;
} else if (!group.equals(other.group))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return false;
}
}
4.8 SaapTriggerState
package com.com.saap.scheduler.model;
/**
* Trigger states {@link SaapTriggerState} for the schedule job.State helps to
* find the actual state of the job as trigger is associated with a job.
*
*
* five states of the trigger are as follows
*
NONE
*
NORMAL
*
PAUSED
*
COMPLETE
*
ERROR
*
BLOCKED
*
*
*
*
*
*/
public enum SaapTriggerState {
NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED
}
5. Service classes
5.1 JobService
package com.com.saap.scheduler.service;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobKey;
public interface JobService {
JobKey createJobKey(final String name);
JobKey createJobKey(final String name, final String group);
JobDetail createJobDetail(Class jobClass, final JobKey jobKey);
}
5.2 JobServiceImpl
package com.com.saap.scheduler.service;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.springframework.stereotype.Service;
@Service
public class JobServiceImpl implements JobService {
@Override
public JobKey createJobKey(String name) {
// TODO Auto-generated method stub
return new JobKey(name);
}
@Override
public JobKey createJobKey(String name, String group) {
// TODO Auto-generated method stub
return new JobKey(name, group);
}
////
@Override
public JobDetail createJobDetail(Class jobClass, JobKey jobKey) {
// TODO Auto-generated method stub
return JobBuilder.newJob(jobClass).withIdentity(jobKey).build();
}
}
5.3 SchedulerService
package com.com.saap.scheduler.service;
import java.util.List;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import com.com.saap.scheduler.model.SaapJob;
@Service
public interface SchedulerService {
/**
* Start scheduler.
*
* @throws SchedulerException
*/
void start() throws SchedulerException;
/**
* Shutdown scheduler.
*
* @throws SchedulerException
*/
void shutdown() throws SchedulerException;
//// jobs
/**
* Returns all the jobs in the scheduler.
*
* @return
* @throws SchedulerException
*/
List getJobList() throws SchedulerException;
/**
* Filter and return the list of jobs in the scheduler.
*
* @param triggerState (NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED)
* @return
* @throws SchedulerException
*/
List getJobList(String triggerState) throws SchedulerException;
/**
* Trigger a selected job.
*
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
void triggerJob(String jobName, String jobGroup) throws SchedulerException;
/**
* Create Job and Trigger. Schedule the Job with created Trigger.
*
* @param JobClass
* @param jobName
* @param jobGroup
* @param triggerName
* @param triggerGroup
* @param cronExpression
* @throws SchedulerException
* @throws ClassNotFoundException
*/
public void sheduleJob(final String JobClass, final String jobName, String jobGroup, final String triggerName,
final String triggerGroup, final String cronExpression, final String sourceURL, final String destURL)
throws SchedulerException, ClassNotFoundException;
/**
* Change the trigger value: cron Expression for the given job.
*
* @param triggerName
* @param triggerGroup
* @param newCronExp
* @throws SchedulerException
*/
void changeTriggerForJob(String triggerName, String triggerGroup, String newCronExp) throws SchedulerException;
/**
* Delete a job.
*
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
void deleteJob(final String jobName, String jobGroup) throws SchedulerException;
/**
* Pause schedule job.
*
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
void pauseJob(String jobName, String jobGroup) throws SchedulerException;
/**
* Resume a given job.
*
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
void resumeJob(String jobName, String jobGroup) throws SchedulerException;
/**
* Interrupt a given job.
*
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
void interruptJob(String jobName, String jobGroup) throws SchedulerException;
/**
* Get the Job details for given job name with corresponding group.
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
SaapJob getJobDetail(String jobName, String jobGroup) throws SchedulerException;
}
5.4 SchedulerServiceImpl
package com.com.saap.scheduler.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.com.saap.scheduler.model.SaapJob;
import com.com.saap.scheduler.model.SaapJobData;
import com.com.saap.scheduler.model.SaapJobDetail;
import com.com.saap.scheduler.model.SaapJobKey;
import com.com.saap.scheduler.model.SaapTrigger;
import com.com.saap.scheduler.model.SaapTriggerKey;
@Service
public class SchedulerServiceImpl implements SchedulerService {
private static Logger LOG = Logger.getLogger(SchedulerServiceImpl.class.getName());
@Autowired
Scheduler scheduler;
@Autowired
TriggerServiceImpl triggerService;
@Autowired
JobServiceImpl jobService;
@Override
public void start() throws SchedulerException {
scheduler.start();
}
@Override
public void shutdown() throws SchedulerException {
scheduler.shutdown();
}
public void addJob(final String JobClass, final String jobName, String jobGroup)
throws SchedulerException, ClassNotFoundException {
JobKey jobKey = jobService.createJobKey(jobName, jobGroup);
JobDetail jobDetail = jobService.createJobDetail((Class) Class.forName(JobClass), jobKey);
scheduler.addJob(jobDetail, true);
}
@Override
public void sheduleJob(final String JobClass, final String jobName, String jobGroup, final String triggerName,
final String triggerGroup, final String cronExpression, final String sourceURL, final String destURL)
throws SchedulerException, ClassNotFoundException {
JobKey jobKey = jobService.createJobKey(jobName, jobGroup);
JobDetail jobDetail = jobService.createJobDetail((Class) Class.forName(JobClass), jobKey);
jobDetail.getJobDataMap().put("sourceURL", sourceURL);
jobDetail.getJobDataMap().put("destinationURL", destURL);
TriggerKey triggerKey = triggerService.createTriggerKey(triggerName, triggerGroup);
Trigger trigger = triggerService.createTrigger(triggerKey, cronExpression);
scheduler.scheduleJob(jobDetail, trigger);
}
@Override
public void deleteJob(final String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = jobService.createJobKey(jobName, jobGroup);
scheduler.deleteJob(jobKey);
}
@Override
public List getJobList() throws SchedulerException {
List saapJobList = new ArrayList();
for (String groupName : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
String jobName = jobKey.getName();
String jobGroup = jobKey.getGroup();
String jobDescription = scheduler.getJobDetail(jobKey).getDescription();
String jobClass = scheduler.getJobDetail(jobKey).getJobClass().getName();
List jobDataList = new ArrayList();
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail.getJobDataMap() != null && jobDetail.getJobDataMap().size() > 0) {
JobDataMap jobDataMap = jobDetail.getJobDataMap();
// check for null pointer
for (Map.Entry entry : jobDataMap.entrySet()) {
SaapJobData jobData = new SaapJobData();
jobData.setKey(entry.getKey());
jobData.setValue(entry.getValue().toString());
jobDataList.add(jobData);
}
}
List triggers = (List) scheduler.getTriggersOfJob(jobKey);
Trigger trigger = triggers.get(0);
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
// create saapJobDetail
SaapJobDetail saapJobDetail = new SaapJobDetail();
saapJobDetail.setJobClass(jobClass);
saapJobDetail.setJobDataList(jobDataList);
saapJobDetail.setJobDescription(jobDescription);
saapJobDetail.setJobKey(new SaapJobKey(jobName, jobGroup));
// create Trigger details
SaapTrigger saapTrigger = new SaapTrigger();
saapTrigger.setCronExpression(cronExpression);
saapTrigger.setDescription(trigger.getDescription());
saapTrigger.setEndTime(trigger.getEndTime());
saapTrigger.setNextFireTime(trigger.getNextFireTime());
saapTrigger.setPreviousFireTime(trigger.getPreviousFireTime());
saapTrigger.setPriority(trigger.getPriority());
saapTrigger.setStartTime(trigger.getStartTime());
saapTrigger.setTriggerKey(new SaapTriggerKey(trigger.getKey().getName(), trigger.getKey().getGroup()));
saapTrigger.setTriggerState(scheduler.getTriggerState(trigger.getKey()).toString());
SaapJob saapJob = new SaapJob(saapJobDetail, saapTrigger);
saapJobList.add(saapJob);
}
}
return saapJobList;
}
@Override
public List getJobList(String triggerState) throws SchedulerException {
// SaapTriggerState.valueOf(triggerState)
Predicate jobPricate = job -> job.getTrigger().getTriggerState().equals(triggerState);
List jobs = getJobList().stream().parallel().filter(jobPricate).collect(Collectors.toList());
return jobs;
}
@Override
public SaapJob getJobDetail(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
// create saapJobDetail
SaapJobDetail saapJobDetail = new SaapJobDetail();
saapJobDetail.setJobClass(jobDetail.getClass().getName());
List jobDataList = new ArrayList();
if (jobDetail.getJobDataMap() != null && jobDetail.getJobDataMap().size() > 0) {
JobDataMap jobDataMap = jobDetail.getJobDataMap();
// check for null pointer
for (Map.Entry entry : jobDataMap.entrySet()) {
SaapJobData jobData = new SaapJobData();
jobData.setKey(entry.getKey());
jobData.setValue(entry.getValue().toString());
jobDataList.add(jobData);
}
}
saapJobDetail.setJobDataList(jobDataList);
saapJobDetail.setJobDescription(jobDetail.getDescription());
saapJobDetail.setJobKey(new SaapJobKey(jobName, jobGroup));
// create Trigger details
List triggers = (List) scheduler.getTriggersOfJob(jobKey);
CronTrigger trigger = (CronTrigger) triggers.get(0);
SaapTrigger saapTrigger = new SaapTrigger();
saapTrigger.setCronExpression(trigger.getCronExpression());
saapTrigger.setDescription(trigger.getDescription());
saapTrigger.setEndTime(trigger.getEndTime());
saapTrigger.setNextFireTime(trigger.getNextFireTime());
saapTrigger.setPreviousFireTime(trigger.getPreviousFireTime());
saapTrigger.setPriority(trigger.getPriority());
saapTrigger.setStartTime(trigger.getStartTime());
saapTrigger.setTriggerKey(new SaapTriggerKey(trigger.getKey().getName(), trigger.getKey().getGroup()));
saapTrigger.setTriggerState(scheduler.getTriggerState(trigger.getKey()).toString());
SaapJob saapJob = new SaapJob(saapJobDetail, saapTrigger);
return saapJob;
}
public void getJobDetails(String jobGroupName) throws SchedulerException {
GroupMatcher.jobGroupEquals(jobGroupName);
List jobGroupList = scheduler.getJobGroupNames();
LOG.info(jobGroupList.toString());
}
public void getCurrentlyRunningJobs() throws SchedulerException {
List list = scheduler.getCurrentlyExecutingJobs();
LOG.info(list.toString());
}
@Override
public void triggerJob(String jobName, String jobGroup) throws SchedulerException {
// create when group is null - for default group
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.triggerJob(jobKey);
}
@Override
public void pauseJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.pauseJob(jobKey);
}
@Override
public void resumeJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.resumeJob(jobKey);
}
@Override
public void interruptJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.interrupt(jobKey);
}
@Override
public void changeTriggerForJob(String triggerName, String triggerGroup, String newCronExp)
throws SchedulerException {
TriggerKey oldTriggerKey = new TriggerKey(triggerName, triggerGroup);
Trigger newTrigger = TriggerBuilder.newTrigger().withIdentity(oldTriggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(newCronExp)).build();
scheduler.rescheduleJob(oldTriggerKey, newTrigger);
}
}
5.5 TriggerService
package com.com.saap.scheduler.service;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
public interface TriggerService {
// trigger
TriggerKey createTriggerKey(final String name);
TriggerKey createTriggerKey(final String name, final String group);
Trigger createTrigger(final TriggerKey triggerKey, final String cronExpression);
}
5.6 TriggerServiceImpl
package com.com.saap.scheduler.service;
import org.quartz.CronScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service;
@Service
public class TriggerServiceImpl implements TriggerService {
@Override
public TriggerKey createTriggerKey(String name) {
// TODO Auto-generated method stub
return new TriggerKey(name);
}
@Override
public TriggerKey createTriggerKey(String name, String group) {
// TODO Auto-generated method stub
return new TriggerKey(name, group);
}
////
@Override
public Trigger createTrigger(TriggerKey triggerKey, String cronExpression) {
// TODO Auto-generated method stub triggerDescription triggerPriority
return TriggerBuilder.newTrigger().withDescription(null).withIdentity(triggerKey)
.withPriority(Trigger.DEFAULT_PRIORITY).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
}
}
6. SaapSchedulerApplication - main class for SpringBoot application
Note: @EnableScheduling
package com.saap.scheduler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SaapSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SaapSchedulerApplication.class, args);
}
}
7. application.properties
# Spring properties
spring.application.name= sheduler-service
#map error
server.error.path: /error
# HTTP Server
server.port=8889
# Discovery Server Access
# 1. DEV ONLY: Reduce the lease renewal interval to speed up registration
# 2. Define URL of registration server (defaultZone)
eureka.client.serviceUrl.defaultZone= http://localhost:1111/eureka/
eureka.instance.leaseRenewalIntervalInSeconds=5
using.spring.schedulerFactory=true
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/qzDS
spring.datasource.username = root
spring.datasource.password = 123
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
## QuartzProperties
spring.quartz.job-store-type=jdbc
#spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql
spring.quartz.properties.org.quartz.threadPool.threadCount=5
8. quartz.properties - not needed as we are using Springboot
##scheduler
#quartz.scheduler.instanceName = MyScheduler
#
## thread-pool
#org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#org.quartz.threadPool.threadCount=2
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
#
## job-store
##org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#
## others
#org.quartz.jobStore.misfireThreshold = 60000
#
## Using JobStoreTX
### Be sure to run the appropriate script(under docs/dbTables) first to create database/tables
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#
## Configuring JDBCJobStore with the Table Prefix
#org.quartz.jobStore.tablePrefix = QRTZ_
#
## Using DriverDelegate
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
## Using datasource
#org.quartz.jobStore.dataSource = qzDS
#
## Define the datasource to use
##org.quartz.dataSource.qzDS.driver = com.ibm.db2.jcc.DB2Driver
##org.quartz.dataSource.qzDS.URL = jdbc:db2://localhost:50000/QZ_SMPL
##org.quartz.dataSource.qzDS.user = wiki_rw
##org.quartz.dataSource.qzDS.password = db24local
##org.quartz.dataSource.qzDS.maxConnections = 30
#org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/qzDS
#org.quartz.dataSource.qzDS.user = root
#org.quartz.dataSource.qzDS.password = 123
##org.quartz.dataSource.qzDS.maxConnections = 30