Wednesday, February 13, 2019

Create quartz scheduler as REST service and persist scheduler data to Database

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
 *
     *


  1. jobClass
  2.  *


  3. jobDescription
  4.  *


  5. jobKey
  6.  *


  7. jobDataList
  8.  *
     *
     * 
     * 
     *
     */
    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;

    /**
     *
     * SaapTriggerss have a {@link SaapTriggerKey} associated with
     * them, which should uniquely identify them within a single
     * {@link Scheduler}.
     *
     * 
     *
     * SaapTriggers are the 'mechanism' by which SaapJobs
     * are scheduled. Many SaapTriggers can point to the same
     * SaapJob, but a single SaapTrigger can only point to
     * one SaapJob.
     *
     * 
     *
     * SaapTriggers can 'send' parameters/data to SaapJobs 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
     *
       *


    1. NONE
    2.  *


    3. NORMAL
    4.  *


    5. PAUSED
    6.  *


    7. COMPLETE
    8.  *


    9. ERROR
    10.  *


    11. BLOCKED
    12.  *
       *
       * 
       * 
       *
       */
      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



      No comments:

      Post a Comment