This commit is contained in:
Fabio Formosa
2021-10-30 16:22:21 +02:00
parent 87ee4bebb3
commit fb2d8da53d
10 changed files with 170 additions and 261 deletions

View File

@@ -91,45 +91,45 @@
<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>
<!-- 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>
<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

@@ -3,8 +3,6 @@ package it.fabioformosa.quartzmanager.configuration;
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.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -17,7 +15,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
import java.io.IOException;
import java.util.Properties;
@@ -27,8 +24,6 @@ import java.util.Properties;
@ConditionalOnProperty(name = "quartz.enabled")
public class SchedulerConfig {
private static final int DEFAULT_MISFIRE_INSTRUCTION = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
private static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass) {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
@@ -36,35 +31,13 @@ public class SchedulerConfig {
return factoryBean;
}
private static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs,
int repeatCount) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(3000L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(repeatCount);
factoryBean
.setMisfireInstruction(DEFAULT_MISFIRE_INSTRUCTION);// in case of misfire, ignore all missed triggers and continue
return factoryBean;
}
@Value("${quartz-manager.jobClass}")
private String jobClassname;
@Autowired(required = false)
private QuartzModuleProperties quartzModuleProperties;
// REMOVEME
// @Bean(name = "triggerMonitor")
// public TriggerMonitor createTriggerMonitor(@Qualifier("jobTrigger") Trigger trigger) {
// TriggerMonitor triggerMonitor = new TriggerMonitorImpl();
// triggerMonitor.setTrigger(trigger);
// return triggerMonitor;
// }
@Bean
@SuppressWarnings("unchecked")
public JobDetailFactoryBean jobDetail() throws ClassNotFoundException {
Class<? extends Job> JobClass = (Class<? extends Job>) Class.forName(jobClassname);
return createJobDetail(JobClass);
@@ -85,24 +58,15 @@ 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 = "scheduler")
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();
mergedProperties.putAll(quartzProperties());
if(quartzModuleProperties != null)
mergedProperties.putAll(quartzModuleProperties.getProperties());
mergedProperties.putAll(quartzProperties());
factory.setQuartzProperties(mergedProperties);
//factory.setTriggers(sampleJobTrigger);
factory.setAutoStartup(false);
return factory;
}

View File

@@ -38,24 +38,15 @@ public class SchedulerController {
this.conversionService = conversionService;
}
// @Resource
// private Scheduler scheduler;
//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;
}
@@ -66,8 +57,6 @@ public class SchedulerController {
return new SchedulerConfigParam(triggersPerDay, maxCount, timesTriggered);
}
@GetMapping
public SchedulerDTO getScheduler() {
log.debug("SCHEDULER - GET Scheduler...");
@@ -114,26 +103,6 @@ public class SchedulerController {
schedulerService.getScheduler().standby();
}
// @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;
// }
@GetMapping("/resume")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void resume() throws SchedulerException {

View File

@@ -5,13 +5,10 @@ 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.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.ConversionService;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@Slf4j
@RequestMapping("/quartz-manager/triggers")
@RestController
@@ -21,83 +18,31 @@ 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;
public TriggerController(SchedulerService schedulerService) {
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;
return schedulerService.getTriggerByName(name);
}
@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()
)
.withIdentity(name)
.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);
log.info("TRIGGER - CREATING a trigger {} {}", name, config);
TriggerDTO newTriggerDTO = schedulerService.scheduleNewTrigger(name, jobClassname, config);
log.info("TRIGGER - CREATED a trigger {}", newTriggerDTO);
return newTriggerDTO;
}
@PutMapping("/{name}")
public TriggerDTO rescheduleTrigger(@PathVariable String name, @RequestBody SchedulerConfigParam config) throws SchedulerException, ClassNotFoundException {
log.info("TRIGGER - RESCHEDULE trigger {}", config);
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
Optional<TriggerKey> optionalTriggerKey = schedulerService.getTriggerByKey(name);
TriggerKey triggerKey = optionalTriggerKey.orElse(TriggerKey.triggerKey(name));
Trigger trigger = scheduler.getTrigger(triggerKey);
Trigger newTrigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalInMills)
.withRepeatCount(config.getMaxCount() - 1)
.withMisfireHandlingInstructionNextWithRemainingCount()
)
.forJob(trigger.getJobKey().getName())
.withIdentity(name)
.build();
// scheduler.scheduleJob(jobDetail, newTrigger);
scheduler.rescheduleJob(triggerKey, newTrigger);
TriggerDTO newTriggerDTO = conversionService.convert(newTrigger, TriggerDTO.class);
log.info("Rescheduled new trigger {}", newTriggerDTO);
return newTriggerDTO;
public TriggerDTO rescheduleTrigger(@PathVariable String name, @RequestBody SchedulerConfigParam config) throws SchedulerException {
log.info("TRIGGER - RESCHEDULING the trigger {} {}", name, config);
TriggerDTO triggerDTO = schedulerService.rescheduleTrigger(name, config);
log.info("TRIGGER - RESCHEDULED the trigger {}", triggerDTO);
return triggerDTO;
}

View File

@@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping(value = "/quartz-manager/api", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
@GetMapping("/whoami")
public @ResponseBody Object user() {
SecurityContext context = SecurityContextHolder.getContext();
@@ -21,12 +20,12 @@ public class UserController {
return "\"NO_AUTH\"";
}
/**
* JWT Temporary disabled
*
* @author Fabio.Formosa
*
*/
// /**
// * JWT Temporary disabled
// *
// * @author Fabio.Formosa
// *
// */
// @Autowired
// private UserService userService;

View File

@@ -1,11 +1,11 @@
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 it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.Optional;
@@ -17,9 +17,11 @@ public class SchedulerService {
public static final int SEC_IN_A_DAY = 60 * 60 * 24;
private Scheduler scheduler;
private ConversionService conversionService;
public SchedulerService(Scheduler scheduler) {
public SchedulerService(Scheduler scheduler, ConversionService conversionService) {
this.scheduler = scheduler;
this.conversionService = conversionService;
}
public static int fromTriggerPerDayToMillsInterval(long triggerPerDay) {
@@ -57,4 +59,56 @@ public class SchedulerService {
.findFirst();
}
public TriggerDTO getTriggerByName(String name) throws SchedulerException {
Trigger trigger = scheduler.getTrigger(new TriggerKey(name));
return conversionService.convert(trigger, TriggerDTO.class);
}
public TriggerDTO scheduleNewTrigger(String name, String jobClassname, SchedulerConfigParam config) throws SchedulerException, ClassNotFoundException {
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(jobClassname);
JobDetail jobDetail = JobBuilder.newJob()
.ofType(jobClass)
.storeDurably(false)
.build();
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
Trigger newTrigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalInMills)
.withRepeatCount(config.getMaxCount() - 1)
.withMisfireHandlingInstructionNextWithRemainingCount()
)
.withIdentity(name)
.build();
scheduler.scheduleJob(jobDetail, newTrigger);
return conversionService.convert(newTrigger, TriggerDTO.class);
}
public TriggerDTO rescheduleTrigger(String name, SchedulerConfigParam config) throws SchedulerException {
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
Optional<TriggerKey> optionalTriggerKey = getTriggerByKey(name);
TriggerKey triggerKey = optionalTriggerKey.orElse(TriggerKey.triggerKey(name));
Trigger trigger = scheduler.getTrigger(triggerKey);
Trigger newTrigger = TriggerBuilder.newTrigger()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(intervalInMills)
.withRepeatCount(config.getMaxCount() - 1)
.withMisfireHandlingInstructionNextWithRemainingCount()
)
.forJob(trigger.getJobKey().getName())
.withIdentity(name)
.build();
scheduler.rescheduleJob(triggerKey, newTrigger);
return conversionService.convert(newTrigger, TriggerDTO.class);
}
}

View File

@@ -41,70 +41,66 @@
</dependency>
<!-- SPRING -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-jpa</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MISC -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<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.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>spring-mock-mvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<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.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>spring-mock-mvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@@ -114,18 +110,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- TO BE REMOVED -->
<!-- <dependency>-->
<!-- <groupId>org.liquibase</groupId>-->
<!-- <artifactId>liquibase-core</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
</dependencies>

View File

@@ -8,10 +8,9 @@ import it.fabioformosa.quartzmanager.jobs.entities.LogRecord.LogType;
public class SampleJob extends AbstractLoggingJob {
@Override
public LogRecord doIt(JobExecutionContext jobExecutionContext) {
return new LogRecord(LogType.INFO, "Hello!");
return new LogRecord(LogType.INFO, "Hello!");
}
}

View File

@@ -13,10 +13,6 @@ spring:
mode: LEGACYHTML5
jpa.open-in-view: false
# quartz:
# org.quartz.jobStore.isClustered: true
# org.quartz.scheduler.instanceId=AUTO
quartz:
enabled: true

View File

@@ -1,3 +1,2 @@
org.quartz.scheduler.instanceName=example
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=1