Changed API and frontend to handle stored triggers and jobs

This commit is contained in:
fabio.formosa
2021-10-17 13:15:54 +02:00
parent 10df1116bd
commit e50a48bd4c
27 changed files with 862 additions and 429 deletions

View File

@@ -108,11 +108,11 @@
"defaultProject": "angular-spring-starter",
"schematics": {
"@schematics/angular:component": {
"prefix": "app",
"prefix": "qrzmng",
"style": "css"
},
"@schematics/angular:directive": {
"prefix": "app"
"prefix": "qrzmng"
}
}
}
}

View File

@@ -2,35 +2,56 @@
<mat-card-header>
<mat-card-title><b>SCHEDULER CONFIG</b></mat-card-title>
</mat-card-header>
<mat-card-content>
<!-- ADD BUTTON -->
<mat-card-content *ngIf="!shouldShowTriggerConfig() && !enabledTriggerForm">
<button mat-fab color="primary">
<mat-icon (click)="enableTriggerForm()">add</mat-icon>
</button>
</mat-card-content>
<!-- TRIGGER DETAILS -->
<mat-card-content *ngIf="shouldShowTriggerConfig() || enabledTriggerForm">
<div fxLayout="column">
<form name="configForm" fxFlex="1 1 100%" #configForm="ngForm">
<mat-form-field>
<input matInput placeholder="Freq [Num per day]" [(ngModel)]="config.triggerPerDay" name="triggerPerDay" type="number">
<mat-form-field >
<input [readonly]="!enabledTriggerForm"
matInput placeholder="Freq [Num per day]" name="triggerPerDay" type="number"
[(ngModel)]="config.triggerPerDay"
>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Max Occurrences" [(ngModel)]="config.maxCount" name="maxCount" type="number">
<input [readonly]="!enabledTriggerForm"
matInput placeholder="Max Occurrences" name="maxCount" type="number"
[(ngModel)]="config.maxCount"
>
</mat-form-field>
<br>
<div>
<h5>Misfire Policy</h5>
<div>RESCHEDULE NEXT WITH REMAINING COUNT</div>
<div class="small">
In case of misfire event, the trigger is re-scheduled to the next scheduled time after 'now' with the repeat count set to what it would be, if it had not missed any firings.
In case of misfire event, the trigger is re-scheduled to the next scheduled time after 'now' with the repeat count set to what it would be, if it had not missed any firings.
<br/>
<strong>Warning:</strong> This policy could cause the Trigger to go directly to the 'COMPLETE' state if all fire-times where missed.
<strong>Warning:</strong> This policy could cause the Trigger to go directly to the 'COMPLETE' state if all fire-times where missed.
</div>
</div>
<br>
<button mat-raised-button
type="button"
type="button"
*ngIf="enabledTriggerForm"
(click)="submitConfig()">
Submit
</button>
<button mat-raised-button type="button"
*ngIf="!enabledTriggerForm"
(click)="enabledTriggerForm = true">
Reschedule
</button>
</form>
</div>
</mat-card-content>

View File

@@ -1,40 +1,65 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { SchedulerService } from '../../services';
import { SchedulerConfig } from '../../model/schedulerConfig.model'
import {Scheduler} from '../../model/scheduler.model';
@Component({
selector: 'scheduler-config',
selector: 'qrzmng-scheduler-config',
templateUrl: './scheduler-config.component.html',
styleUrls: ['./scheduler-config.component.scss']
})
export class SchedulerConfigComponent implements OnInit {
config: SchedulerConfig = new SchedulerConfig()
configBackup: SchedulerConfig = new SchedulerConfig()
scheduler: Scheduler;
triggerLoading = true;
enabledTriggerForm = false;
private fetchedTriggers = false;
private triggerInProgress = false;
constructor(
private schedulerService: SchedulerService
) { }
config : SchedulerConfig = new SchedulerConfig()
configBackup : SchedulerConfig = new SchedulerConfig()
ngOnInit() {
this.retrieveConfig()
this.triggerLoading = true;
this._getScheduler();
this.retrieveConfig();
}
retrieveConfig = () => {
this.schedulerService.getConfig()
.subscribe(res => {
this.config = new SchedulerConfig(res.triggerPerDay, res.maxCount)
this.config = new SchedulerConfig(res.triggerPerDay, res.maxCount, res.timesTriggered)
this.configBackup = res
this.triggerLoading = false;
this.triggerInProgress = res.timesTriggered < res.maxCount;
})
}
private _getScheduler() {
this.schedulerService.getScheduler()
.subscribe( res => {
this.scheduler = <Scheduler>res;
this.fetchedTriggers = this.scheduler.triggerKeys.length > 0
})
}
shouldShowTriggerConfig = (): boolean => this.fetchedTriggers && this.triggerInProgress;
submitConfig = () => {
this.schedulerService.updateConfig(this.config)
.subscribe(res => {
this.configBackup = this.config;
this.enabledTriggerForm = false;
this.fetchedTriggers = true;
this.triggerInProgress = true;
}, error => {
this.config = this.configBackup;
});
};
enableTriggerForm = () => this.enabledTriggerForm = true;
}

View File

@@ -0,0 +1,13 @@
import {TriggerKey} from './triggerKey.model';
export class Scheduler {
name: string;
instanceId: string;
triggerKeys: TriggerKey[];
constructor(name: string, instanceId: string, triggerKeys: TriggerKey[]) {
this.name = name;
this.instanceId = instanceId;
this.triggerKeys = triggerKeys;
}
}

View File

@@ -1,11 +1,13 @@
export class SchedulerConfig {
triggerPerDay : number = 0
maxCount : number = 0
triggerPerDay = 0;
maxCount = 0;
timesTriggered = 0;
constructor(triggerPerDay = 0, maxCount = 0) {
this.triggerPerDay = triggerPerDay
this.maxCount = maxCount
constructor(triggerPerDay = 0, maxCount = 0, timesTriggered = 0) {
this.triggerPerDay = triggerPerDay;
this.maxCount = maxCount;
this.timesTriggered = timesTriggered;
}
}
}

View File

@@ -0,0 +1,9 @@
export class TriggerKey {
name: string;
group: string;
constructor(name: string, group: string) {
this.name = name;
this.group = group;
}
}

View File

@@ -12,20 +12,24 @@ export class SchedulerService {
startScheduler = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/run')
}
stopScheduler = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/stop')
}
pauseScheduler = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/pause')
}
resumeScheduler = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/resume')
}
getStatus = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/status')
}
getScheduler = () => {
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler')
}
@@ -34,6 +38,8 @@ export class SchedulerService {
}
updateConfig = (config: Object) => {
return this.apiService.post(getBaseUrl() + '/quartz-manager/scheduler/config', config)
return this.apiService.post(getBaseUrl() + '/quartz-manager/triggers/mytrigger', config)
}
}

View File

@@ -4,16 +4,16 @@
<div fxLayout="column">
<scheduler-control></scheduler-control>
<br/>
<scheduler-config></scheduler-config>
<qrzmng-scheduler-config></qrzmng-scheduler-config>
</div>
</div>
</div>
<div fxFlex="1 1 70%" style="margin-left: 20px">
<div fxLayout="column">
<div fxFlex="1 1 100%"><progress-panel></progress-panel></div>
<br/>
<div fxFlex="1 1 100%"><logs-panel></logs-panel></div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,54 @@
package it.fabioformosa.quartzmanager.common.utils;
import java.util.function.Function;
public class Try<R> {
private final Throwable failure;
private final R success;
public Try(Throwable failure, R success) {
this.failure = failure;
this.success = success;
}
public R getSuccess() {
return success;
}
public static <R> Try success(R r){
return new Try<>(null, r);
}
public static <ExceptionType> Try failure(Throwable e){
return new Try<>(e, null);
}
public static <T, R> Function<T, Try<R>> with(CheckedFunction<T, R> checkedFunction){
return t -> {
try {
return Try.success(checkedFunction.apply(t));
} catch (java.lang.Exception e) {
return Try.failure(e);
}
};
}
public static <T, R> Function<T, R> sneakyThrow(CheckedFunction<T, R> checkedFunction){
return t -> Try.with(checkedFunction).apply(t).getSuccess();
}
public boolean isSuccess(){
return this.failure == null;
}
public boolean isFailure(){
return this.failure != null;
}
@FunctionalInterface
public static interface CheckedFunction<T, R> {
R apply(T t) throws java.lang.Exception;
}
}

View File

@@ -1,128 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>it.fabioformosa.quartz-manager</groupId>
<artifactId>quartz-manager-parent</artifactId>
<version>3.0.2-SNAPSHOT</version>
</parent>
<artifactId>quartz-manager-starter-api</artifactId>
<name>Quartz Manager Starter API</name>
<description>REST API layer for your scheduler and triggered jobs, to be included in your spring webapp</description>
<url>https://github.com/fabioformosa/quartz-manager</url>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<springfox.version>2.9.2</springfox.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>it.fabioformosa.quartz-manager</groupId>
<artifactId>quartz-manager-common</artifactId>
</dependency>
<!-- SPRING -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MISC -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- QUARTZ -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Reactor -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-net</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>io.projectreactor.spring</groupId>
<artifactId>reactor-spring-context</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- SWAGGER -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.version}</version>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>it.fabioformosa.quartz-manager</groupId>
<artifactId>quartz-manager-parent</artifactId>
<version>3.0.2-SNAPSHOT</version>
</parent>
<artifactId>quartz-manager-starter-api</artifactId>
<name>Quartz Manager Starter API</name>
<description>REST API layer for your scheduler and triggered jobs, to be included in your spring webapp</description>
<url>https://github.com/fabioformosa/quartz-manager</url>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<springfox.version>2.9.2</springfox.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>it.fabioformosa.quartz-manager</groupId>
<artifactId>quartz-manager-common</artifactId>
</dependency>
<!-- SPRING -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MISC -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>it.fabioformosa</groupId>
<artifactId>metamorphosis-core</artifactId>
<version>3.0.0</version>
</dependency>
<!-- QUARTZ -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Reactor -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-net</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>io.projectreactor.spring</groupId>
<artifactId>reactor-spring-context</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- SWAGGER -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,9 +1,8 @@
package it.fabioformosa.quartzmanager.aspects;
import javax.annotation.Resource;
import it.fabioformosa.quartzmanager.dto.TriggerStatus;
import it.fabioformosa.quartzmanager.services.SchedulerService;
import org.quartz.DailyTimeIntervalTrigger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
@@ -11,8 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Component;
import it.fabioformosa.quartzmanager.dto.TriggerStatus;
import it.fabioformosa.quartzmanager.scheduler.TriggerMonitor;
import javax.annotation.Resource;
/**
*
@@ -28,11 +26,14 @@ public class WebSocketProgressNotifier implements ProgressNotifier {
@Autowired
private SimpMessageSendingOperations messagingTemplate;
@Resource
private Scheduler scheduler;
// @Resource
// private Scheduler scheduler;
@Resource
private TriggerMonitor triggerMonitor;
private SchedulerService schedulerService;
// @Resource
// private TriggerMonitor triggerMonitor;
//@AfterReturning("execution(* logAndSend(..))")
// @Override
@@ -44,7 +45,7 @@ public class WebSocketProgressNotifier implements ProgressNotifier {
public void send() throws SchedulerException {
TriggerStatus currTriggerStatus = new TriggerStatus();
Trigger trigger = scheduler.getTrigger(triggerMonitor.getTrigger().getKey());
Trigger trigger = schedulerService.getOneSimpleTrigger().get();
currTriggerStatus.setFinalFireTime(trigger.getFinalFireTime());
currTriggerStatus.setNextFireTime(trigger.getNextFireTime());
currTriggerStatus.setPreviousFireTime(trigger.getPreviousFireTime());
@@ -62,7 +63,7 @@ public class WebSocketProgressNotifier implements ProgressNotifier {
repeatCount = dailyTrigger.getRepeatCount();
}
Trigger jobTrigger = triggerMonitor.getTrigger();
Trigger jobTrigger = schedulerService.getOneSimpleTrigger().get();
if (jobTrigger != null && jobTrigger.getJobKey() != null) {
currTriggerStatus.setJobKey(jobTrigger.getJobKey().getName());
currTriggerStatus.setJobClass(jobTrigger.getClass().getSimpleName());

View File

@@ -0,0 +1,9 @@
package it.fabioformosa.quartzmanager.configuration;
import it.fabioformosa.metamorphosis.core.EnableMetamorphosisConversions;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableMetamorphosisConversions(basePackages = { "it.fabioformosa.quartzmanager" })
public class ConversionConfig {
}

View File

@@ -1,15 +1,12 @@
package it.fabioformosa.quartzmanager.configuration;
import java.io.IOException;
import java.util.Properties;
import it.fabioformosa.quartzmanager.common.properties.QuartzModuleProperties;
import it.fabioformosa.quartzmanager.scheduler.AutowiringSpringBeanJobFactory;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -22,10 +19,8 @@ import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
import it.fabioformosa.quartzmanager.common.properties.QuartzModuleProperties;
import it.fabioformosa.quartzmanager.scheduler.AutowiringSpringBeanJobFactory;
import it.fabioformosa.quartzmanager.scheduler.TriggerMonitor;
import it.fabioformosa.quartzmanager.scheduler.TriggerMonitorImpl;
import java.io.IOException;
import java.util.Properties;
@ComponentScan(basePackages = {"it.fabioformosa.quartzmanager.controllers"})
@Configuration
@@ -59,12 +54,14 @@ public class SchedulerConfig {
@Autowired(required = false)
private QuartzModuleProperties quartzModuleProperties;
@Bean(name = "triggerMonitor")
public TriggerMonitor createTriggerMonitor(@Qualifier("jobTrigger") Trigger trigger) {
TriggerMonitor triggerMonitor = new TriggerMonitorImpl();
triggerMonitor.setTrigger(trigger);
return triggerMonitor;
}
// REMOVEME
// @Bean(name = "triggerMonitor")
// public TriggerMonitor createTriggerMonitor(@Qualifier("jobTrigger") Trigger trigger) {
// TriggerMonitor triggerMonitor = new TriggerMonitorImpl();
// triggerMonitor.setTrigger(trigger);
// return triggerMonitor;
// }
@Bean
@SuppressWarnings("unchecked")
@@ -88,15 +85,16 @@ public class SchedulerConfig {
return propertiesFactoryBean.getObject();
}
@Bean(name = "jobTrigger")
public SimpleTriggerFactoryBean sampleJobTrigger(@Qualifier("jobDetail") JobDetail jobDetail,
@Value("${job.frequency}") long frequency, @Value("${job.repeatCount}") int repeatCount) {
return createTrigger(jobDetail, frequency, repeatCount);
}
// @Bean(name = "jobTrigger")
// public SimpleTriggerFactoryBean sampleJobTrigger(@Qualifier("jobDetail") JobDetail jobDetail,
// @Value("${job.frequency}") long frequency, @Value("${job.repeatCount}") int repeatCount) {
// return createTrigger(jobDetail, frequency, repeatCount);
// }
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory,
@Qualifier("jobTrigger") Trigger sampleJobTrigger) throws IOException {
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException {
// public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory,
// @Qualifier("jobTrigger") Trigger sampleJobTrigger) throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(jobFactory);
Properties mergedProperties = new Properties();
@@ -104,8 +102,8 @@ public class SchedulerConfig {
if(quartzModuleProperties != null)
mergedProperties.putAll(quartzModuleProperties.getProperties());
factory.setQuartzProperties(mergedProperties);
factory.setTriggers(sampleJobTrigger);
//factory.setTriggers(sampleJobTrigger);
factory.setAutoStartup(false);
return factory;
}
}
}

View File

@@ -1,161 +1,158 @@
package it.fabioformosa.quartzmanager.controllers;
import java.util.Collections;
import java.util.Map;
import javax.annotation.Resource;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
import it.fabioformosa.quartzmanager.dto.SchedulerDTO;
import it.fabioformosa.quartzmanager.dto.TriggerStatus;
import it.fabioformosa.quartzmanager.enums.SchedulerStates;
import it.fabioformosa.quartzmanager.scheduler.TriggerMonitor;
import it.fabioformosa.quartzmanager.services.SchedulerService;
import org.quartz.*;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map;
/**
* This controller provides scheduler info about config and status. It provides
* also methods to set new config and start/stop/resume the scheduler.
*
* @author Fabio.Formosa
*
*/
@RestController
@RequestMapping("/quartz-manager/scheduler")
@Api(value = "scheduler")
public class SchedulerController {
private static final int MILLS_IN_A_DAY = 1000 * 60 * 60 * 24;
private static final int SEC_IN_A_DAY = 60 * 60 * 24;
private final Logger log = LoggerFactory.getLogger(SchedulerController.class);
private final Logger log = LoggerFactory.getLogger(SchedulerController.class);
private SchedulerService schedulerService;
@Resource
private Scheduler scheduler;
public SchedulerController(SchedulerService schedulerService, ConversionService conversionService) {
this.schedulerService = schedulerService;
this.conversionService = conversionService;
}
@Resource
private TriggerMonitor triggerMonitor;
// @Resource
// private Scheduler scheduler;
private long fromMillsIntervalToTriggerPerDay(long repeatIntervalInMills) {
return (int) Math.ceil(MILLS_IN_A_DAY / repeatIntervalInMills);
//TODO REMOVEME
// @Resource
// private TriggerMonitor triggerMonitor;
@Resource
private ConversionService conversionService;
@GetMapping("/config")
public SchedulerConfigParam getConfig() throws SchedulerException {
log.debug("SCHEDULER - GET CONFIG params");
SchedulerConfigParam schedulerConfigParam = schedulerService.getOneSimpleTrigger()
.map(SchedulerController::fromSimpleTriggerToSchedulerConfigParam)
.orElse(new SchedulerConfigParam(0, 0, 0));
return schedulerConfigParam;
}
public static SchedulerConfigParam fromSimpleTriggerToSchedulerConfigParam(SimpleTrigger simpleTrigger){
int timesTriggered = simpleTrigger.getTimesTriggered();
int maxCount = simpleTrigger.getRepeatCount() + 1;
long triggersPerDay = SchedulerService.fromMillsIntervalToTriggerPerDay(simpleTrigger.getRepeatInterval());
return new SchedulerConfigParam(triggersPerDay, maxCount, timesTriggered);
}
@GetMapping
public SchedulerDTO getScheduler() {
log.debug("SCHEDULER - GET Scheduler...");
SchedulerDTO schedulerDTO = conversionService.convert(schedulerService.getScheduler(), SchedulerDTO.class);
return schedulerDTO;
}
@GetMapping("/progress")
public TriggerStatus getProgressInfo() throws SchedulerException {
log.trace("SCHEDULER - GET PROGRESS INFO");
TriggerStatus progress = new TriggerStatus();
SimpleTriggerImpl jobTrigger = (SimpleTriggerImpl) schedulerService.getOneSimpleTrigger().get();
if (jobTrigger != null && jobTrigger.getJobKey() != null) {
progress.setJobKey(jobTrigger.getJobKey().getName());
progress.setJobClass(jobTrigger.getClass().getSimpleName());
progress.setTimesTriggered(jobTrigger.getTimesTriggered());
progress.setRepeatCount(jobTrigger.getRepeatCount());
progress.setFinalFireTime(jobTrigger.getFinalFireTime());
progress.setNextFireTime(jobTrigger.getNextFireTime());
progress.setPreviousFireTime(jobTrigger.getPreviousFireTime());
}
private int fromTriggerPerDayToMillsInterval(long triggerPerDay) {
return (int) Math.ceil(Long.valueOf(MILLS_IN_A_DAY) / triggerPerDay); // with ceil the triggerPerDay is a max value
}
return progress;
}
@SuppressWarnings("unused")
private int fromTriggerPerDayToSecInterval(long triggerPerDay) {
return (int) Math.ceil(Long.valueOf(SEC_IN_A_DAY) / triggerPerDay);
}
@GetMapping(value = "/status", produces = "application/json")
public Map<String, String> getStatus() throws SchedulerException {
log.trace("SCHEDULER - GET STATUS");
String schedulerState = "";
if (schedulerService.getScheduler().isShutdown() || !schedulerService.getScheduler().isStarted())
schedulerState = SchedulerStates.STOPPED.toString();
else if (schedulerService.getScheduler().isStarted() && schedulerService.getScheduler().isInStandbyMode())
schedulerState = SchedulerStates.PAUSED.toString();
else
schedulerState = SchedulerStates.RUNNING.toString();
return Collections.singletonMap("data", schedulerState.toLowerCase());
}
@GetMapping("/config")
public SchedulerConfigParam getConfig() throws SchedulerException {
log.debug("SCHEDULER - GET CONFIG params");
@GetMapping("/pause")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void pause() throws SchedulerException {
log.info("SCHEDULER - PAUSE COMMAND");
schedulerService.getScheduler().standby();
}
SimpleTrigger jobTrigger = (SimpleTrigger) scheduler.getTrigger(triggerMonitor.getTrigger().getKey());
int maxCount = jobTrigger.getRepeatCount() + 1;
long triggersPerDay = fromMillsIntervalToTriggerPerDay(jobTrigger.getRepeatInterval());
// @PostMapping("/config")
// public SchedulerConfigParam postConfig(@RequestBody SchedulerConfigParam config) throws SchedulerException {
// log.info("SCHEDULER - NEW CONFIG {}", config);
//
// int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
//
// Trigger newTrigger = TriggerBuilder.newTrigger()
// .withSchedule(
// SimpleScheduleBuilder.simpleSchedule()
// .withIntervalInMilliseconds(intervalInMills)
// .withRepeatCount(config.getMaxCount() - 1)
// .withMisfireHandlingInstructionNextWithRemainingCount()
// )
// .build();
//
// schedulerService.getScheduler().rescheduleJob(schedulerService.getOneTriggerKey().get(), newTrigger);
//// triggerMonitor.setTrigger(newTrigger); REMOVEME
// return config;
// }
return new SchedulerConfigParam(triggersPerDay, maxCount);
}
@GetMapping("/resume")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void resume() throws SchedulerException {
log.info("SCHEDULER - RESUME COMMAND");
schedulerService.getScheduler().start();
}
@GetMapping("/progress")
public TriggerStatus getProgressInfo() throws SchedulerException {
log.trace("SCHEDULER - GET PROGRESS INFO");
TriggerStatus progress = new TriggerStatus();
@GetMapping("/run")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void run() throws SchedulerException {
log.info("SCHEDULER - START COMMAND");
schedulerService.getScheduler().start();
}
SimpleTriggerImpl jobTrigger = (SimpleTriggerImpl) scheduler.getTrigger(triggerMonitor.getTrigger().getKey());
if (jobTrigger != null && jobTrigger.getJobKey() != null) {
progress.setJobKey(jobTrigger.getJobKey().getName());
progress.setJobClass(jobTrigger.getClass().getSimpleName());
progress.setTimesTriggered(jobTrigger.getTimesTriggered());
progress.setRepeatCount(jobTrigger.getRepeatCount());
progress.setFinalFireTime(jobTrigger.getFinalFireTime());
progress.setNextFireTime(jobTrigger.getNextFireTime());
progress.setPreviousFireTime(jobTrigger.getPreviousFireTime());
}
return progress;
}
@GetMapping(produces = "application/json")
public Map<String, String> getStatus() throws SchedulerException {
log.trace("SCHEDULER - GET STATUS");
String schedulerState = "";
if (scheduler.isShutdown() || !scheduler.isStarted())
schedulerState = SchedulerStates.STOPPED.toString();
else if (scheduler.isStarted() && scheduler.isInStandbyMode())
schedulerState = SchedulerStates.PAUSED.toString();
else
schedulerState = SchedulerStates.RUNNING.toString();
return Collections.singletonMap("data", schedulerState.toLowerCase());
}
@GetMapping("/pause")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void pause() throws SchedulerException {
log.info("SCHEDULER - PAUSE COMMAND");
scheduler.standby();
}
@PostMapping("/config")
public SchedulerConfigParam postConfig(@RequestBody SchedulerConfigParam config) throws SchedulerException {
log.info("SCHEDULER - NEW CONFIG {}", config);
SimpleTrigger trigger = (SimpleTrigger) triggerMonitor.getTrigger();
TriggerBuilder<SimpleTrigger> triggerBuilder = trigger.getTriggerBuilder();
int intervalInMills = fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
Trigger newTrigger = triggerBuilder
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalInMills)
.withRepeatCount(config.getMaxCount() - 1)
.withMisfireHandlingInstructionNextWithRemainingCount()
)
.build();
scheduler.rescheduleJob(triggerMonitor.getTrigger().getKey(), newTrigger);
triggerMonitor.setTrigger(newTrigger);
return config;
}
@GetMapping("/resume")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void resume() throws SchedulerException {
log.info("SCHEDULER - RESUME COMMAND");
scheduler.start();
}
@GetMapping("/run")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void run() throws SchedulerException {
log.info("SCHEDULER - START COMMAND");
scheduler.start();
}
@GetMapping("/stop")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void stop() throws SchedulerException {
log.info("SCHEDULER - STOP COMMAND");
scheduler.shutdown(true);
}
@GetMapping("/stop")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void stop() throws SchedulerException {
log.info("SCHEDULER - STOP COMMAND");
schedulerService.getScheduler().shutdown(true);
}
}

View File

@@ -0,0 +1,72 @@
package it.fabioformosa.quartzmanager.controllers;
import io.swagger.annotations.Api;
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
import it.fabioformosa.quartzmanager.services.SchedulerService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.ConversionService;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RequestMapping("/quartz-manager/triggers")
@RestController
@Api(value = "triggers")
public class TriggerController {
@Value("${quartz-manager.jobClass}")
private String jobClassname;
private Scheduler scheduler;
private SchedulerService schedulerService;
private ConversionService conversionService;
public TriggerController(Scheduler scheduler, SchedulerService schedulerService, ConversionService conversionService) {
this.scheduler = scheduler;
this.schedulerService = schedulerService;
this.conversionService = conversionService;
}
@GetMapping("/{name}")
public TriggerDTO getTrigger(@PathVariable String name) throws SchedulerException {
Trigger trigger = scheduler.getTrigger(new TriggerKey(name));
TriggerDTO triggerDTO = conversionService.convert(trigger, TriggerDTO.class);
return triggerDTO;
}
@PostMapping("/{name}")
public TriggerDTO postTrigger(@PathVariable String name, @RequestBody SchedulerConfigParam config) throws SchedulerException, ClassNotFoundException {
log.info("TRIGGER - POST trigger {}", config);
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(jobClassname);
JobDetail jobDetail = JobBuilder.newJob()
.ofType(jobClass)
.storeDurably(false)
.build();
Trigger newTrigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalInMills)
.withRepeatCount(config.getMaxCount() - 1)
.withMisfireHandlingInstructionNextWithRemainingCount()
)
.build();
// Optional<TriggerKey> optionalTriggerKey = schedulerService.getTriggerByKey(name);
// TriggerKey triggerKey = optionalTriggerKey.orElse(TriggerKey.triggerKey(name));
scheduler.scheduleJob(jobDetail, newTrigger);
// scheduler.rescheduleJob(triggerKey, newTrigger);
TriggerDTO newTriggerDTO = conversionService.convert(newTrigger, TriggerDTO.class);
log.info("Rescheduled new trigger {}", newTriggerDTO);
return newTriggerDTO;
}
}

View File

@@ -0,0 +1,15 @@
package it.fabioformosa.quartzmanager.converters;
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
import it.fabioformosa.quartzmanager.dto.JobKeyDTO;
import org.quartz.JobKey;
import org.springframework.stereotype.Component;
@Component
public class JobKeyToJobKeyDTO extends AbstractBaseConverterToDTO<JobKey, JobKeyDTO> {
@Override
protected void convert(JobKey source, JobKeyDTO target) {
target.setName(source.getName());
target.setGroup(source.getGroup());
}
}

View File

@@ -0,0 +1,21 @@
package it.fabioformosa.quartzmanager.converters;
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
import it.fabioformosa.quartzmanager.dto.SchedulerDTO;
import lombok.SneakyThrows;
import org.quartz.Scheduler;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Component;
@Component
public class SchedulerToSchedulerDTO extends AbstractBaseConverterToDTO<Scheduler, SchedulerDTO> {
@SneakyThrows
@Override
protected void convert(Scheduler source, SchedulerDTO target) {
target.setName(source.getSchedulerName());
target.setInstanceId(source.getSchedulerInstanceId());
target.setTriggerKeys(source.getTriggerKeys(GroupMatcher.anyTriggerGroup()));
}
}

View File

@@ -0,0 +1,16 @@
package it.fabioformosa.quartzmanager.converters;
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
import it.fabioformosa.quartzmanager.dto.TriggerKeyDTO;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Component;
@Component
public class TriggerKeyToTriggerKeyDTO extends AbstractBaseConverterToDTO<TriggerKey, TriggerKeyDTO> {
@Override
protected void convert(TriggerKey source, TriggerKeyDTO target) {
target.setName(source.getName());
target.setGroup(source.getGroup());
}
}

View File

@@ -0,0 +1,36 @@
package it.fabioformosa.quartzmanager.converters;
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
import it.fabioformosa.quartzmanager.dto.JobKeyDTO;
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
import it.fabioformosa.quartzmanager.dto.TriggerKeyDTO;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Component;
@Component
public class TriggerToTriggerDTO extends AbstractBaseConverterToDTO<Trigger, TriggerDTO> {
@Override
protected void convert(Trigger source, TriggerDTO target) {
TriggerKey triggerKey = source.getKey();
TriggerKeyDTO triggerKeyDTO = conversionService.convert(triggerKey, TriggerKeyDTO.class);
target.setTriggerKeyDTO(triggerKeyDTO);
target.setStartTime(source.getStartTime());
target.setDescription(source.getDescription());
target.setEndTime(source.getEndTime());
target.setFinalFireTime(source.getFinalFireTime());
target.setMisfireInstruction(source.getMisfireInstruction());
target.setNextFireTime(source.getNextFireTime());
target.setPriority(source.getPriority());
target.setMayFireAgain(source.mayFireAgain());
JobKey jobKey = source.getJobKey();
JobKeyDTO jobKeyDTO = conversionService.convert(jobKey, JobKeyDTO.class);
target.setJobKeyDTO(jobKeyDTO);
}
}

View File

@@ -0,0 +1,22 @@
package it.fabioformosa.quartzmanager.dto;
public class JobKeyDTO {
private String name;
private String group;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGroup(String group) {
this.group = group;
}
public String getGroup() {
return group;
}
}

View File

@@ -1,40 +1,14 @@
package it.fabioformosa.quartzmanager.dto;
public class SchedulerConfigParam {
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class SchedulerConfigParam {
public long triggerPerDay;
public int maxCount;
public SchedulerConfigParam() {
super();
}
public SchedulerConfigParam(long triggerPerDay, int maxCount) {
super();
this.triggerPerDay = triggerPerDay;
this.maxCount = maxCount;
}
public int getMaxCount() {
return maxCount;
}
public long getTriggerPerDay() {
return triggerPerDay;
}
public void setMaxCount(int maxCount) {
this.maxCount = maxCount;
}
public void setTriggerPerDay(long triggerPerDay) {
this.triggerPerDay = triggerPerDay;
}
@Override
public String toString() {
return "SchedulerConfigParam [triggerPerDay=" + triggerPerDay
+ ", maxCount=" + maxCount + "]";
}
public int timesTriggered;
}

View File

@@ -0,0 +1,35 @@
package it.fabioformosa.quartzmanager.dto;
import org.quartz.TriggerKey;
import java.util.Set;
public class SchedulerDTO {
private String name;
private String instanceId;
private Set<TriggerKey> triggerKeys;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
public String getInstanceId() {
return instanceId;
}
public void setTriggerKeys(Set<TriggerKey> triggerKeys) {
this.triggerKeys = triggerKeys;
}
public Set<TriggerKey> getTriggerKeys() {
return triggerKeys;
}
}

View File

@@ -0,0 +1,23 @@
package it.fabioformosa.quartzmanager.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class TriggerDTO {
private TriggerKeyDTO triggerKeyDTO;
private int priority;
private Date startTime;
private String description;
private Date endTime;
private Date finalFireTime;
private int misfireInstruction;
private Date nextFireTime;
private JobKeyDTO jobKeyDTO;
private boolean mayFireAgain;
}

View File

@@ -0,0 +1,22 @@
package it.fabioformosa.quartzmanager.dto;
public class TriggerKeyDTO {
private String name;
private String group;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGroup(String group) {
this.group = group;
}
public String getGroup() {
return group;
}
}

View File

@@ -0,0 +1,60 @@
package it.fabioformosa.quartzmanager.services;
import it.fabioformosa.quartzmanager.common.utils.Try;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class SchedulerService {
public static final int MILLS_IN_A_DAY = 1000 * 60 * 60 * 24;
public static final int SEC_IN_A_DAY = 60 * 60 * 24;
private Scheduler scheduler;
public SchedulerService(Scheduler scheduler) {
this.scheduler = scheduler;
}
public static int fromTriggerPerDayToMillsInterval(long triggerPerDay) {
return (int) Math.ceil(Long.valueOf(SchedulerService.MILLS_IN_A_DAY) / triggerPerDay); // with ceil the triggerPerDay is a max value
}
public static int fromTriggerPerDayToSecInterval(long triggerPerDay) {
return (int) Math.ceil(Long.valueOf(SchedulerService.SEC_IN_A_DAY) / triggerPerDay);
}
public static long fromMillsIntervalToTriggerPerDay(long repeatIntervalInMills) {
return (int) Math.ceil(MILLS_IN_A_DAY / repeatIntervalInMills);
}
public Scheduler getScheduler() {
return scheduler;
}
public Optional<TriggerKey> getTriggerByKey(String triggerKeyName) throws SchedulerException {
return scheduler.getTriggerKeys(GroupMatcher.anyGroup()).stream()
.filter(triggerKey -> triggerKey.getName().equals(triggerKeyName))
.findFirst();
}
public Optional<SimpleTrigger> getOneSimpleTrigger() throws SchedulerException {
return getOneTriggerKey()
.map(Try.with(triggerKey -> scheduler.getTrigger(triggerKey)))
.filter(Try::isSuccess).map(Try::getSuccess)
.filter(trigger -> trigger instanceof SimpleTrigger)
.map(trigger -> (SimpleTrigger) trigger);
}
public Optional<TriggerKey> getOneTriggerKey() throws SchedulerException {
return scheduler.getTriggerKeys(GroupMatcher.anyGroup()).stream()
.findFirst();
}
}

View File

@@ -1,69 +1,61 @@
package it.fabioformosa.quartzmanager.persistence;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import it.fabioformosa.quartzmanager.common.properties.QuartzModuleProperties;
import liquibase.integration.spring.SpringLiquibase;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
@PropertySource("classpath:quartz-manager-application-persistence.properties")
public class PersistenceConfig {
@Data
public class PersistenceDatasourceProps {
private String url;
private String changeLog;
private String contexts;
private String user;
private String password;
}
// @Data
// public class QuartzModuleProperties{
// private Properties properties;
// }
@Bean
public SpringLiquibase liquibase(PersistenceDatasourceProps persistenceDatasourceProps, DataSource quartzManagerDatasource) {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setContexts(persistenceDatasourceProps.getContexts());
liquibase.setChangeLog(persistenceDatasourceProps.getChangeLog());
liquibase.setDataSource(quartzManagerDatasource);
liquibase.setDropFirst(false);
return liquibase;
}
@Bean
@ConfigurationProperties(prefix = "spring.liquibase")
public PersistenceDatasourceProps persistenceDatasourceProps() {
return new PersistenceDatasourceProps();
}
@Bean("quartzPersistenceProperties")
@ConfigurationProperties(prefix = "spring.quartz")
public QuartzModuleProperties persistenceQuartzProps() {
return new QuartzModuleProperties();
}
@Primary
@Bean
public DataSource quartzManagerDatasource(PersistenceDatasourceProps persistenceDatasourceProps) {
return DataSourceBuilder.create()
.url(persistenceDatasourceProps.getUrl())
.driverClassName("org.postgresql.Driver")
.username(persistenceDatasourceProps.getUser())
.password(persistenceDatasourceProps.getPassword())
.build();
}
}
package it.fabioformosa.quartzmanager.persistence;
import it.fabioformosa.quartzmanager.common.properties.QuartzModuleProperties;
import liquibase.integration.spring.SpringLiquibase;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration
@PropertySource("classpath:quartz-manager-application-persistence.properties")
public class PersistenceConfig {
@Data
public class PersistenceDatasourceProps {
private String url;
private String changeLog;
private String contexts;
private String user;
private String password;
}
@Bean
public SpringLiquibase liquibase(PersistenceDatasourceProps persistenceDatasourceProps, DataSource quartzManagerDatasource) {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setContexts(persistenceDatasourceProps.getContexts());
liquibase.setChangeLog(persistenceDatasourceProps.getChangeLog());
liquibase.setDataSource(quartzManagerDatasource);
liquibase.setDropFirst(false);
return liquibase;
}
@Bean
@ConfigurationProperties(prefix = "spring.liquibase")
public PersistenceDatasourceProps persistenceDatasourceProps() {
return new PersistenceDatasourceProps();
}
@Bean("quartzPersistenceProperties")
@ConfigurationProperties(prefix = "spring.quartz")
public QuartzModuleProperties persistenceQuartzProps() {
return new QuartzModuleProperties();
}
@Primary
@Bean
public DataSource quartzManagerDatasource(PersistenceDatasourceProps persistenceDatasourceProps) {
return DataSourceBuilder.create()
.url(persistenceDatasourceProps.getUrl())
.driverClassName("org.postgresql.Driver")
.username(persistenceDatasourceProps.getUser())
.password(persistenceDatasourceProps.getPassword())
.build();
}
}

View File

@@ -12,6 +12,9 @@
<logger name="it.fabioformosa" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenAuthenticationFilter" level="WARN" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.springframework" level="WARN" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
@@ -23,4 +26,4 @@
<appender-ref ref="STDOUT" />
</root>
</configuration>
</configuration>