mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2026-05-14 22:00:30 +09:00
#56 added the simpleTrigger to the API
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package it.fabioformosa.quartzmanager.aspects;
|
||||
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,6 @@ import org.quartz.SchedulerException;
|
||||
*/
|
||||
public interface ProgressNotifier {
|
||||
|
||||
void send() throws SchedulerException;
|
||||
void send(JobExecutionContext jobExecutionContext) throws SchedulerException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
package it.fabioformosa.quartzmanager.aspects;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerStatus;
|
||||
import it.fabioformosa.quartzmanager.services.SchedulerService;
|
||||
import org.quartz.DailyTimeIntervalTrigger;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessageSendingOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* Notify the progress of the trigger through websocket
|
||||
@@ -29,8 +23,8 @@ public class WebSocketProgressNotifier implements ProgressNotifier {
|
||||
// @Resource
|
||||
// private Scheduler scheduler;
|
||||
|
||||
@Resource
|
||||
private SchedulerService schedulerService;
|
||||
// @Resource
|
||||
// private LegacySchedulerService schedulerService;
|
||||
|
||||
// @Resource
|
||||
// private TriggerMonitor triggerMonitor;
|
||||
@@ -42,34 +36,26 @@ public class WebSocketProgressNotifier implements ProgressNotifier {
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void send() throws SchedulerException {
|
||||
public void send(JobExecutionContext jobExecutionContext) throws SchedulerException {
|
||||
TriggerStatus currTriggerStatus = new TriggerStatus();
|
||||
|
||||
Trigger trigger = schedulerService.getOneSimpleTrigger().get();
|
||||
Trigger trigger = jobExecutionContext.getTrigger();
|
||||
currTriggerStatus.setFinalFireTime(trigger.getFinalFireTime());
|
||||
currTriggerStatus.setNextFireTime(trigger.getNextFireTime());
|
||||
currTriggerStatus.setPreviousFireTime(trigger.getPreviousFireTime());
|
||||
|
||||
int timesTriggered = 0;
|
||||
int repeatCount = 0;
|
||||
|
||||
if (trigger instanceof SimpleTrigger) {
|
||||
SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
|
||||
timesTriggered = simpleTrigger.getTimesTriggered();
|
||||
repeatCount = simpleTrigger.getRepeatCount();
|
||||
currTriggerStatus.setRepeatCount(simpleTrigger.getRepeatCount() + 1);
|
||||
currTriggerStatus.setTimesTriggered(simpleTrigger.getTimesTriggered());
|
||||
} else if (trigger instanceof DailyTimeIntervalTrigger) {
|
||||
DailyTimeIntervalTrigger dailyTrigger = (DailyTimeIntervalTrigger) trigger;
|
||||
timesTriggered = dailyTrigger.getTimesTriggered();
|
||||
repeatCount = dailyTrigger.getRepeatCount();
|
||||
currTriggerStatus.setRepeatCount(dailyTrigger.getRepeatCount() + 1);
|
||||
}
|
||||
|
||||
Trigger jobTrigger = schedulerService.getOneSimpleTrigger().get();
|
||||
if (jobTrigger != null && jobTrigger.getJobKey() != null) {
|
||||
currTriggerStatus.setJobKey(jobTrigger.getJobKey().getName());
|
||||
currTriggerStatus.setJobClass(jobTrigger.getClass().getSimpleName());
|
||||
currTriggerStatus.setTimesTriggered(timesTriggered);
|
||||
currTriggerStatus.setRepeatCount(repeatCount + 1);
|
||||
}
|
||||
JobDetail jobDetail = jobExecutionContext.getJobDetail();
|
||||
currTriggerStatus.setJobKey(jobDetail.getKey().getName());
|
||||
currTriggerStatus.setJobClass(trigger.getClass().getSimpleName());
|
||||
|
||||
messagingTemplate.convertAndSend("/topic/progress", currTriggerStatus);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package it.fabioformosa.quartzmanager.controllers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
public class AbstractTriggerController {
|
||||
|
||||
@Value("${quartz-manager.jobClass}")
|
||||
protected String jobClassname;
|
||||
|
||||
}
|
||||
@@ -10,7 +10,7 @@ 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.services.SchedulerService;
|
||||
import it.fabioformosa.quartzmanager.services.LegacySchedulerService;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.quartz.impl.triggers.SimpleTriggerImpl;
|
||||
@@ -40,10 +40,10 @@ public class SchedulerController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(SchedulerController.class);
|
||||
|
||||
private SchedulerService schedulerService;
|
||||
private LegacySchedulerService legacySchedulerService;
|
||||
|
||||
public SchedulerController(SchedulerService schedulerService, ConversionService conversionService) {
|
||||
this.schedulerService = schedulerService;
|
||||
public SchedulerController(LegacySchedulerService legacySchedulerService, ConversionService conversionService) {
|
||||
this.legacySchedulerService = legacySchedulerService;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class SchedulerController {
|
||||
})
|
||||
public SchedulerConfigParam getConfig() throws SchedulerException {
|
||||
log.debug("SCHEDULER - GET CONFIG params");
|
||||
SchedulerConfigParam schedulerConfigParam = schedulerService.getOneSimpleTrigger()
|
||||
SchedulerConfigParam schedulerConfigParam = legacySchedulerService.getOneSimpleTrigger()
|
||||
.map(SchedulerController::fromSimpleTriggerToSchedulerConfigParam)
|
||||
.orElse(new SchedulerConfigParam(0L, 0, 0));
|
||||
return schedulerConfigParam;
|
||||
@@ -69,7 +69,7 @@ public class SchedulerController {
|
||||
public static SchedulerConfigParam fromSimpleTriggerToSchedulerConfigParam(SimpleTrigger simpleTrigger){
|
||||
int timesTriggered = simpleTrigger.getTimesTriggered();
|
||||
int maxCount = simpleTrigger.getRepeatCount() + 1;
|
||||
long triggersPerDay = SchedulerService.fromMillsIntervalToTriggerPerDay(simpleTrigger.getRepeatInterval());
|
||||
long triggersPerDay = LegacySchedulerService.fromMillsIntervalToTriggerPerDay(simpleTrigger.getRepeatInterval());
|
||||
return new SchedulerConfigParam(triggersPerDay, maxCount, timesTriggered);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class SchedulerController {
|
||||
})
|
||||
public SchedulerDTO getScheduler() {
|
||||
log.debug("SCHEDULER - GET Scheduler...");
|
||||
SchedulerDTO schedulerDTO = conversionService.convert(schedulerService.getScheduler(), SchedulerDTO.class);
|
||||
SchedulerDTO schedulerDTO = conversionService.convert(legacySchedulerService.getScheduler(), SchedulerDTO.class);
|
||||
return schedulerDTO;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SchedulerController {
|
||||
log.trace("SCHEDULER - GET PROGRESS INFO");
|
||||
TriggerStatus progress = new TriggerStatus();
|
||||
|
||||
SimpleTriggerImpl jobTrigger = (SimpleTriggerImpl) schedulerService.getOneSimpleTrigger().get();
|
||||
SimpleTriggerImpl jobTrigger = (SimpleTriggerImpl) legacySchedulerService.getOneSimpleTrigger().get();
|
||||
if (jobTrigger != null && jobTrigger.getJobKey() != null) {
|
||||
progress.setJobKey(jobTrigger.getJobKey().getName());
|
||||
progress.setJobClass(jobTrigger.getClass().getSimpleName());
|
||||
@@ -122,9 +122,9 @@ public class SchedulerController {
|
||||
public Map<String, String> getStatus() throws SchedulerException {
|
||||
log.trace("SCHEDULER - GET STATUS");
|
||||
String schedulerState = "";
|
||||
if (schedulerService.getScheduler().isShutdown() || !schedulerService.getScheduler().isStarted())
|
||||
if (legacySchedulerService.getScheduler().isShutdown() || !legacySchedulerService.getScheduler().isStarted())
|
||||
schedulerState = SchedulerStates.STOPPED.toString();
|
||||
else if (schedulerService.getScheduler().isStarted() && schedulerService.getScheduler().isInStandbyMode())
|
||||
else if (legacySchedulerService.getScheduler().isStarted() && legacySchedulerService.getScheduler().isInStandbyMode())
|
||||
schedulerState = SchedulerStates.PAUSED.toString();
|
||||
else
|
||||
schedulerState = SchedulerStates.RUNNING.toString();
|
||||
@@ -139,7 +139,7 @@ public class SchedulerController {
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
public void pause() throws SchedulerException {
|
||||
log.info("SCHEDULER - PAUSE COMMAND");
|
||||
schedulerService.getScheduler().standby();
|
||||
legacySchedulerService.getScheduler().standby();
|
||||
}
|
||||
|
||||
@GetMapping("/resume")
|
||||
@@ -150,7 +150,7 @@ public class SchedulerController {
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
public void resume() throws SchedulerException {
|
||||
log.info("SCHEDULER - RESUME COMMAND");
|
||||
schedulerService.getScheduler().start();
|
||||
legacySchedulerService.getScheduler().start();
|
||||
}
|
||||
|
||||
@GetMapping("/run")
|
||||
@@ -161,7 +161,7 @@ public class SchedulerController {
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
public void run() throws SchedulerException {
|
||||
log.info("SCHEDULER - START COMMAND");
|
||||
schedulerService.getScheduler().start();
|
||||
legacySchedulerService.getScheduler().start();
|
||||
}
|
||||
|
||||
@GetMapping("/stop")
|
||||
@@ -172,7 +172,7 @@ public class SchedulerController {
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
public void stop() throws SchedulerException {
|
||||
log.info("SCHEDULER - STOP COMMAND");
|
||||
schedulerService.getScheduler().shutdown(true);
|
||||
legacySchedulerService.getScheduler().shutdown(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package it.fabioformosa.quartzmanager.controllers;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerCommandDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerInputDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import it.fabioformosa.quartzmanager.services.SimpleTriggerSchedulerService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@Slf4j
|
||||
@RequestMapping(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL)
|
||||
@SecurityRequirement(name = "basic-auth")
|
||||
@RestController
|
||||
public class SimpleTriggerController extends AbstractTriggerController {
|
||||
|
||||
static public final String SIMPLE_TRIGGER_CONTROLLER_BASE_URL = "/quartz-manager/simple-triggers";
|
||||
|
||||
private SimpleTriggerSchedulerService simpleSchedulerService;
|
||||
|
||||
public SimpleTriggerController(SimpleTriggerSchedulerService simpleSchedulerService) {
|
||||
this.simpleSchedulerService = simpleSchedulerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{name}")
|
||||
@Operation(summary = "Get a simple trigger by name")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Got the trigger by its name",
|
||||
content = { @Content(mediaType = "application/json",
|
||||
schema = @Schema(implementation = SimpleTriggerDTO.class)) }),
|
||||
@ApiResponse(responseCode = "404", description = "Trigger not found",
|
||||
content = @Content)
|
||||
})
|
||||
public SimpleTriggerDTO getSimpleTrigger(@PathVariable String name) throws SchedulerException, TriggerNotFoundException {
|
||||
return simpleSchedulerService.getSimpleTriggerByName(name);
|
||||
}
|
||||
|
||||
@PostMapping("/{name}")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@Operation(summary = "Create a new simple trigger")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "201", description = "Created a new simple trigger",
|
||||
content = { @Content(mediaType = "application/json",
|
||||
schema = @Schema(implementation = TriggerDTO.class)) }),
|
||||
@ApiResponse(responseCode = "400", description = "Invalid config supplied",
|
||||
content = @Content)
|
||||
})
|
||||
public SimpleTriggerDTO postSimpleTrigger(@PathVariable String name, @Valid @RequestBody SimpleTriggerInputDTO simpleTriggerInputDTO) throws SchedulerException, ClassNotFoundException {
|
||||
log.info("SIMPLE TRIGGER - CREATING a SimpleTrigger {} {}", name, simpleTriggerInputDTO);
|
||||
SimpleTriggerCommandDTO simpleTriggerCommandDTO = SimpleTriggerCommandDTO.builder()
|
||||
.triggerName(name)
|
||||
.simpleTriggerInputDTO(simpleTriggerInputDTO)
|
||||
.build();
|
||||
SimpleTriggerDTO newTriggerDTO = simpleSchedulerService.scheduleSimpleTrigger(jobClassname, simpleTriggerCommandDTO);
|
||||
log.info("SIMPLE TRIGGER - CREATED a SimpleTrigger {}", newTriggerDTO);
|
||||
return newTriggerDTO;
|
||||
}
|
||||
|
||||
@PutMapping("/{name}")
|
||||
@Operation(summary = "Reschedule a simple trigger")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Rescheduled a simple trigger",
|
||||
content = { @Content(mediaType = "application/json",
|
||||
schema = @Schema(implementation = TriggerDTO.class)) }),
|
||||
@ApiResponse(responseCode = "400", description = "Invalid config supplied",
|
||||
content = @Content)
|
||||
})
|
||||
public TriggerDTO rescheduleSimpleTrigger(@PathVariable String name, @Valid @RequestBody SimpleTriggerInputDTO simpleTriggerInputDTO) throws SchedulerException {
|
||||
log.info("SIMPLE TRIGGER - RESCHEDULING the trigger {} {}", name, simpleTriggerInputDTO);
|
||||
SimpleTriggerCommandDTO simpleTriggerCommandDTO = SimpleTriggerCommandDTO.builder()
|
||||
.triggerName(name)
|
||||
.simpleTriggerInputDTO(simpleTriggerInputDTO)
|
||||
.build();
|
||||
TriggerDTO triggerDTO = simpleSchedulerService.rescheduleSimpleTrigger(simpleTriggerCommandDTO);
|
||||
log.info("SIMPLE TRIGGER - RESCHEDULED the trigger {}", triggerDTO);
|
||||
return triggerDTO;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -8,10 +8,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.services.SchedulerService;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import it.fabioformosa.quartzmanager.services.LegacySchedulerService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -21,24 +21,23 @@ import javax.validation.Valid;
|
||||
@RequestMapping(TriggerController.TRIGGER_CONTROLLER_BASE_URL)
|
||||
@SecurityRequirement(name = "basic-auth")
|
||||
@RestController
|
||||
public class TriggerController {
|
||||
public class TriggerController extends AbstractTriggerController {
|
||||
|
||||
static public final String TRIGGER_CONTROLLER_BASE_URL = "/quartz-manager/triggers";
|
||||
static public final String SIMPLE_TRIGGER_BASE_URL = "/simple-triggers";
|
||||
|
||||
@Value("${quartz-manager.jobClass}")
|
||||
private String jobClassname;
|
||||
private LegacySchedulerService schedulerService;
|
||||
|
||||
private SchedulerService schedulerService;
|
||||
|
||||
public TriggerController(SchedulerService schedulerService) {
|
||||
public TriggerController(LegacySchedulerService schedulerService) {
|
||||
this.schedulerService = schedulerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{name}")
|
||||
public TriggerDTO getTrigger(@PathVariable String name) throws SchedulerException {
|
||||
return schedulerService.getTriggerByName(name);
|
||||
public TriggerDTO getTrigger(@PathVariable String name) throws SchedulerException, TriggerNotFoundException {
|
||||
return schedulerService.getLegacyTriggerByName(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@PostMapping("/{name}")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@Operation(summary = "Create a new trigger")
|
||||
@@ -56,6 +55,8 @@ public class TriggerController {
|
||||
return newTriggerDTO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@PutMapping("/{name}")
|
||||
@Operation(summary = "Reschedule the trigger")
|
||||
@ApiResponses(value = {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package it.fabioformosa.quartzmanager.controllers.advices;
|
||||
|
||||
import it.fabioformosa.quartzmanager.exceptions.ExceptionResponse;
|
||||
import it.fabioformosa.quartzmanager.exceptions.ResourceConflictException;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ControllerAdvice
|
||||
public class ExceptionHandlingController {
|
||||
|
||||
@ExceptionHandler(ResourceConflictException.class)
|
||||
public ResponseEntity<ExceptionResponse> resourceConflict(ResourceConflictException ex) {
|
||||
ExceptionResponse response = new ExceptionResponse();
|
||||
response.setErrorCode("Conflict");
|
||||
response.setErrorMessage(ex.getMessage());
|
||||
return new ResponseEntity<ExceptionResponse>(response, HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
@ExceptionHandler(TriggerNotFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
@ResponseBody
|
||||
public ExceptionResponse triggerNotFound(TriggerNotFoundException ex){
|
||||
return ExceptionResponse.builder().errorCode(HttpStatus.NOT_FOUND.toString()).errorMessage(ex.getMessage()).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package it.fabioformosa.quartzmanager.converters;
|
||||
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerCommandDTO;
|
||||
import org.quartz.SimpleScheduleBuilder;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerBuilder;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SimpleTriggerCommandDTOToSimpleTrigger implements Converter<SimpleTriggerCommandDTO, SimpleTrigger> {
|
||||
@Override
|
||||
public SimpleTrigger convert(SimpleTriggerCommandDTO triggerCommandDTO) {
|
||||
TriggerBuilder<Trigger> triggerTriggerBuilder = TriggerBuilder.newTrigger();
|
||||
if(triggerCommandDTO.getSimpleTriggerInputDTO().getStartDate() != null)
|
||||
triggerTriggerBuilder.startAt(triggerCommandDTO.getSimpleTriggerInputDTO().getStartDate());
|
||||
if(triggerCommandDTO.getSimpleTriggerInputDTO().getEndDate() != null)
|
||||
triggerTriggerBuilder.endAt(triggerCommandDTO.getSimpleTriggerInputDTO().getEndDate());
|
||||
|
||||
SimpleTrigger newSimpleTrigger = triggerTriggerBuilder.withSchedule(
|
||||
SimpleScheduleBuilder.simpleSchedule()
|
||||
.withIntervalInMilliseconds(triggerCommandDTO.getSimpleTriggerInputDTO().getRepeatInterval())
|
||||
.withRepeatCount(triggerCommandDTO.getSimpleTriggerInputDTO().getRepeatCount())
|
||||
.withMisfireHandlingInstructionNextWithRemainingCount()
|
||||
)
|
||||
.withIdentity(triggerCommandDTO.getTriggerName())
|
||||
.build();
|
||||
return newSimpleTrigger;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package it.fabioformosa.quartzmanager.converters;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerDTO;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SimpleTriggerToSimpleTriggerDTO extends TriggerToTriggerDTO<SimpleTrigger, SimpleTriggerDTO> {
|
||||
|
||||
@Override
|
||||
protected void convert(SimpleTrigger source, SimpleTriggerDTO target) {
|
||||
super.convert(source, target);
|
||||
target.setTimesTriggered(source.getTimesTriggered());
|
||||
target.setRepeatCount(source.getRepeatCount());
|
||||
target.setRepeatInterval(source.getRepeatInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleTriggerDTO createOrRetrieveTarget(SimpleTrigger source) {
|
||||
return new SimpleTriggerDTO();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package it.fabioformosa.quartzmanager.converters;
|
||||
|
||||
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
|
||||
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverter;
|
||||
import it.fabioformosa.quartzmanager.dto.JobKeyDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerKeyDTO;
|
||||
@@ -10,10 +10,10 @@ import org.quartz.TriggerKey;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TriggerToTriggerDTO extends AbstractBaseConverterToDTO<Trigger, TriggerDTO> {
|
||||
public class TriggerToTriggerDTO<S extends Trigger, T extends TriggerDTO> extends AbstractBaseConverter<S, T> {
|
||||
|
||||
@Override
|
||||
protected void convert(Trigger source, TriggerDTO target) {
|
||||
protected void convert(S source, T target) {
|
||||
TriggerKey triggerKey = source.getKey();
|
||||
TriggerKeyDTO triggerKeyDTO = conversionService.convert(triggerKey, TriggerKeyDTO.class);
|
||||
target.setTriggerKeyDTO(triggerKeyDTO);
|
||||
@@ -30,7 +30,11 @@ public class TriggerToTriggerDTO extends AbstractBaseConverterToDTO<Trigger, Tri
|
||||
JobKey jobKey = source.getJobKey();
|
||||
JobKeyDTO jobKeyDTO = conversionService.convert(jobKey, JobKeyDTO.class);
|
||||
target.setJobKeyDTO(jobKeyDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T createOrRetrieveTarget(S source) {
|
||||
return (T) new TriggerDTO();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@ToString
|
||||
public class SimpleTriggerCommandDTO {
|
||||
private String triggerName;
|
||||
private SimpleTriggerInputDTO simpleTriggerInputDTO;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@NoArgsConstructor @AllArgsConstructor
|
||||
@Data
|
||||
@ToString(callSuper = true) @EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
public class SimpleTriggerDTO extends TriggerDTO{
|
||||
|
||||
private int repeatCount;
|
||||
private long repeatInterval;
|
||||
private int timesTriggered;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class SimpleTriggerInputDTO extends TriggerCommandDTO {
|
||||
|
||||
@NotNull
|
||||
private Integer repeatCount;
|
||||
|
||||
@NotNull
|
||||
Long repeatInterval;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@Data
|
||||
public class TriggerCommandDTO {
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
private Date startDate;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
private Date endDate;
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Builder
|
||||
@SuperBuilder
|
||||
public class TriggerDTO {
|
||||
private TriggerKeyDTO triggerKeyDTO;
|
||||
private int priority;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.exceptions;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class ExceptionHandlingController {
|
||||
|
||||
@ExceptionHandler(ResourceConflictException.class)
|
||||
public ResponseEntity<ExceptionResponse> resourceConflict(ResourceConflictException ex) {
|
||||
ExceptionResponse response = new ExceptionResponse();
|
||||
response.setErrorCode("Conflict");
|
||||
response.setErrorMessage(ex.getMessage());
|
||||
return new ResponseEntity<ExceptionResponse>(response, HttpStatus.CONFLICT);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,15 @@
|
||||
package it.fabioformosa.quartzmanager.exceptions;
|
||||
|
||||
public class ExceptionResponse {
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
public class ExceptionResponse {
|
||||
private String errorCode;
|
||||
private String errorMessage;
|
||||
|
||||
public ExceptionResponse() {}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode(String errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package it.fabioformosa.quartzmanager.exceptions;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter @Setter
|
||||
public class ResourceConflictException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1791564636123821405L;
|
||||
@@ -8,14 +12,7 @@ public class ResourceConflictException extends RuntimeException {
|
||||
|
||||
public ResourceConflictException(Long resourceId, String message) {
|
||||
super(message);
|
||||
setResourceId(resourceId);
|
||||
}
|
||||
|
||||
public Long getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
public void setResourceId(Long resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package it.fabioformosa.quartzmanager.exceptions;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@Getter
|
||||
public class TriggerNotFoundException extends Exception {
|
||||
|
||||
private String name;
|
||||
|
||||
public TriggerNotFoundException(String name) {
|
||||
super("Trigger with name " + name + " not found!");
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package it.fabioformosa.quartzmanager.jobs;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import it.fabioformosa.quartzmanager.aspects.ProgressNotifier;
|
||||
import it.fabioformosa.quartzmanager.jobs.entities.LogRecord;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.SchedulerException;
|
||||
@@ -10,13 +10,12 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessageSendingOperations;
|
||||
|
||||
import it.fabioformosa.quartzmanager.aspects.ProgressNotifier;
|
||||
import it.fabioformosa.quartzmanager.jobs.entities.LogRecord;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* Extends this class to create a job that produces LogRecord to be displayed
|
||||
* into the GUI panel
|
||||
*
|
||||
*
|
||||
* @author Fabio.Formosa
|
||||
*
|
||||
*/
|
||||
@@ -42,7 +41,7 @@ public abstract class AbstractLoggingJob implements Job {
|
||||
try {
|
||||
LogRecord logMsg = doIt(jobExecutionContext);
|
||||
logAndSend(logMsg);
|
||||
progressNotifier.send();
|
||||
progressNotifier.send(jobExecutionContext);
|
||||
} catch (SchedulerException e) {
|
||||
log.error("Error updating progress " + e.getMessage());
|
||||
}
|
||||
@@ -54,4 +53,4 @@ public abstract class AbstractLoggingJob implements Job {
|
||||
messagingTemplate.convertAndSend("/topic/logs", logRecord);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package it.fabioformosa.quartzmanager.services;
|
||||
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerKey;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
public class AbstractSchedulerService {
|
||||
|
||||
protected Scheduler scheduler;
|
||||
protected ConversionService conversionService;
|
||||
|
||||
public AbstractSchedulerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
this.scheduler = scheduler;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
protected Trigger getTriggerByName(String name) throws SchedulerException, TriggerNotFoundException {
|
||||
Trigger trigger = scheduler.getTrigger(new TriggerKey(name));
|
||||
if(trigger == null)
|
||||
throw new TriggerNotFoundException(name);
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package it.fabioformosa.quartzmanager.services;
|
||||
import it.fabioformosa.quartzmanager.common.utils.Try;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
@@ -10,26 +11,24 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.quartz.TriggerBuilder.newTrigger;
|
||||
|
||||
@Service
|
||||
public class SchedulerService {
|
||||
public class LegacySchedulerService extends AbstractSchedulerService {
|
||||
|
||||
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;
|
||||
private ConversionService conversionService;
|
||||
|
||||
public SchedulerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
this.scheduler = scheduler;
|
||||
this.conversionService = conversionService;
|
||||
public LegacySchedulerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
super(scheduler, conversionService);
|
||||
}
|
||||
|
||||
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
|
||||
return (int) Math.ceil(Long.valueOf(LegacySchedulerService.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);
|
||||
return (int) Math.ceil(Long.valueOf(LegacySchedulerService.SEC_IN_A_DAY) / triggerPerDay);
|
||||
}
|
||||
|
||||
public static long fromMillsIntervalToTriggerPerDay(long repeatIntervalInMills) {
|
||||
@@ -59,10 +58,12 @@ 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 getLegacyTriggerByName(String name) throws SchedulerException, TriggerNotFoundException {
|
||||
Trigger trigger = getTriggerByName(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);
|
||||
@@ -71,9 +72,9 @@ public class SchedulerService {
|
||||
.storeDurably(false)
|
||||
.build();
|
||||
|
||||
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
|
||||
int intervalInMills = LegacySchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
|
||||
|
||||
Trigger newTrigger = TriggerBuilder.newTrigger()
|
||||
Trigger newTrigger = newTrigger()
|
||||
.withSchedule(
|
||||
SimpleScheduleBuilder.simpleSchedule()
|
||||
.withIntervalInMilliseconds(intervalInMills)
|
||||
@@ -88,14 +89,16 @@ public class SchedulerService {
|
||||
return conversionService.convert(newTrigger, TriggerDTO.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public TriggerDTO rescheduleTrigger(String name, SchedulerConfigParam config) throws SchedulerException {
|
||||
int intervalInMills = SchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
|
||||
int intervalInMills = LegacySchedulerService.fromTriggerPerDayToMillsInterval(config.getTriggerPerDay());
|
||||
|
||||
Optional<TriggerKey> optionalTriggerKey = getTriggerByKey(name);
|
||||
TriggerKey triggerKey = optionalTriggerKey.orElse(TriggerKey.triggerKey(name));
|
||||
Trigger trigger = scheduler.getTrigger(triggerKey);
|
||||
|
||||
Trigger newTrigger = TriggerBuilder.newTrigger()
|
||||
Trigger newTrigger = newTrigger()
|
||||
.withSchedule(
|
||||
SimpleScheduleBuilder.simpleSchedule()
|
||||
.withIntervalInMilliseconds(intervalInMills)
|
||||
@@ -0,0 +1,48 @@
|
||||
package it.fabioformosa.quartzmanager.services;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerCommandDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import org.quartz.*;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SimpleTriggerSchedulerService extends AbstractSchedulerService {
|
||||
|
||||
public SimpleTriggerSchedulerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
super(scheduler, conversionService);
|
||||
}
|
||||
|
||||
public SimpleTriggerDTO getSimpleTriggerByName(String name) throws SchedulerException, TriggerNotFoundException {
|
||||
Trigger trigger = getTriggerByName(name);
|
||||
return conversionService.convert(trigger, SimpleTriggerDTO.class);
|
||||
}
|
||||
|
||||
public SimpleTriggerDTO scheduleSimpleTrigger(String jobClassname, SimpleTriggerCommandDTO triggerCommandDTO) throws SchedulerException, ClassNotFoundException {
|
||||
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(jobClassname);
|
||||
JobDetail jobDetail = JobBuilder.newJob()
|
||||
.ofType(jobClass)
|
||||
.storeDurably(false)
|
||||
.build();
|
||||
|
||||
SimpleTrigger newSimpleTrigger = conversionService.convert(triggerCommandDTO, SimpleTrigger.class);
|
||||
scheduler.scheduleJob(jobDetail, newSimpleTrigger);
|
||||
|
||||
return conversionService.convert(newSimpleTrigger, SimpleTriggerDTO.class);
|
||||
}
|
||||
|
||||
public TriggerDTO rescheduleSimpleTrigger(SimpleTriggerCommandDTO triggerCommandDTO) throws SchedulerException {
|
||||
//Optional<TriggerKey> optionalTriggerKey = getTriggerByKey(name);
|
||||
// TriggerKey triggerKey = optionalTriggerKey.orElse(TriggerKey.triggerKey(name));
|
||||
|
||||
SimpleTrigger newSimpleTrigger = conversionService.convert(triggerCommandDTO, SimpleTrigger.class);
|
||||
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(triggerCommandDTO.getTriggerName());
|
||||
scheduler.rescheduleJob(triggerKey, newSimpleTrigger);
|
||||
|
||||
return conversionService.convert(newSimpleTrigger, SimpleTriggerDTO.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package it.fabioformosa.quartzmanager.controllers;
|
||||
|
||||
import it.fabioformosa.quartzmanager.QuartManagerApplicationTests;
|
||||
import it.fabioformosa.quartzmanager.controllers.utils.InvalidSimpleTriggerCommandDTOProvider;
|
||||
import it.fabioformosa.quartzmanager.controllers.utils.TestUtils;
|
||||
import it.fabioformosa.quartzmanager.controllers.utils.TriggerUtils;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerCommandDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerInputDTO;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import it.fabioformosa.quartzmanager.services.SimpleTriggerSchedulerService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
|
||||
@ContextConfiguration(classes = {QuartManagerApplicationTests.class})
|
||||
@WebMvcTest(controllers = SimpleTriggerController.class, properties = {
|
||||
"quartz-manager.jobClass=it.fabioformosa.quartzmanager.jobs.SampleJob"
|
||||
})
|
||||
class SimpleTriggerControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private SimpleTriggerSchedulerService simpleTriggerSchedulerService;
|
||||
|
||||
@AfterEach
|
||||
void cleanUp(){
|
||||
Mockito.reset(simpleTriggerSchedulerService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenGetIsCalled_thenASimpleTriggerIsReturned() throws Exception {
|
||||
SimpleTriggerDTO expectedSimpleTriggerDTO = TriggerUtils.getSimpleTriggerInstance("mytrigger");
|
||||
Mockito.when(simpleTriggerSchedulerService.getSimpleTriggerByName("mytrigger")).thenReturn(expectedSimpleTriggerDTO);
|
||||
|
||||
mockMvc.perform(get(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.content().json(TestUtils.toJson(expectedSimpleTriggerDTO)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAnExistingTrigger_whenGetIsCalled_then404IsReturned() throws Exception {
|
||||
Mockito.when(simpleTriggerSchedulerService.getSimpleTriggerByName("not_existing_trigger_name")).thenThrow(new TriggerNotFoundException("not_existing_trigger_name"));
|
||||
|
||||
mockMvc.perform(get(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/not_existing_trigger_name")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenASimpleTriggerCommandDTO_whenPosted_thenANewSimpleTriggerIsCreated() throws Exception {
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = buildSimpleTriggerCommandDTO();
|
||||
SimpleTriggerDTO expectedSimpleTriggerDTO = TriggerUtils.getSimpleTriggerInstance("mytrigger", simpleTriggerInputDTO);
|
||||
Mockito.when(simpleTriggerSchedulerService.scheduleSimpleTrigger(any(), any())).thenReturn(expectedSimpleTriggerDTO);
|
||||
mockMvc.perform(
|
||||
post(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(TestUtils.toJson(simpleTriggerInputDTO))
|
||||
)
|
||||
.andExpect(MockMvcResultMatchers.status().isCreated())
|
||||
.andExpect(MockMvcResultMatchers.content().json(TestUtils.toJson(expectedSimpleTriggerDTO)))
|
||||
;
|
||||
}
|
||||
|
||||
private SimpleTriggerInputDTO buildSimpleTriggerCommandDTO() {
|
||||
return SimpleTriggerInputDTO.builder()
|
||||
.startDate(new Date())
|
||||
.repeatCount(20)
|
||||
.repeatInterval(20000L)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(InvalidSimpleTriggerCommandDTOProvider.class)
|
||||
void givenAnInvalidSimpleTriggerCommandDTO_whenPostedANewTrigger_thenAnErrorIsReturned(SimpleTriggerInputDTO invalidSimpleTriggerComandDTO) throws Exception {
|
||||
mockMvc.perform(post(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(TestUtils.toJson(invalidSimpleTriggerComandDTO)))
|
||||
.andExpect(MockMvcResultMatchers.status().is4xxClientError());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenATriggerName_whenPutSimpleTriggerCommandDTO_thenTheSimpleTriggerIsRescheduled() throws Exception {
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = buildSimpleTriggerCommandDTO();
|
||||
SimpleTriggerDTO expectedSimpleTriggerDTO = TriggerUtils.getSimpleTriggerInstance("mytrigger", simpleTriggerInputDTO);
|
||||
SimpleTriggerCommandDTO simpleTriggerCommandDTO = SimpleTriggerCommandDTO.builder()
|
||||
.triggerName("mytrigger")
|
||||
.simpleTriggerInputDTO(simpleTriggerInputDTO)
|
||||
.build();
|
||||
Mockito.when(simpleTriggerSchedulerService.rescheduleSimpleTrigger(simpleTriggerCommandDTO)).thenReturn(expectedSimpleTriggerDTO);
|
||||
|
||||
mockMvc.perform(put(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(TestUtils.toJson(simpleTriggerInputDTO)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.content().json(TestUtils.toJson(expectedSimpleTriggerDTO)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(InvalidSimpleTriggerCommandDTOProvider.class)
|
||||
void givenAnInvalidSimpleTriggerCommandDTO_whenATriggerIsRescheduled_thenAnErrorIsReturned(SimpleTriggerInputDTO invalidSimpleTriggerCommandTO) throws Exception {
|
||||
mockMvc.perform(put(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(TestUtils.toJson(invalidSimpleTriggerCommandTO)))
|
||||
.andExpect(MockMvcResultMatchers.status().is4xxClientError());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import it.fabioformosa.quartzmanager.controllers.utils.TestUtils;
|
||||
import it.fabioformosa.quartzmanager.controllers.utils.TriggerUtils;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.services.SchedulerService;
|
||||
import it.fabioformosa.quartzmanager.services.LegacySchedulerService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -25,7 +25,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||
|
||||
@ContextConfiguration(classes = {QuartManagerApplicationTests.class})
|
||||
@WebMvcTest(controllers = TriggerController.class, properties = {
|
||||
"quartz-manager.jobClass=it.fabioformosa.quartzmanager.jobs.myjobs.SampleJob"
|
||||
"quartz-manager.jobClass=it.fabioformosa.quartzmanager.jobs.SampleJob"
|
||||
})
|
||||
class TriggerControllerTest {
|
||||
|
||||
@@ -33,7 +33,7 @@ class TriggerControllerTest {
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private SchedulerService schedulerService;
|
||||
private LegacySchedulerService schedulerService;
|
||||
|
||||
@AfterEach
|
||||
void cleanUp(){
|
||||
@@ -67,7 +67,7 @@ class TriggerControllerTest {
|
||||
@Test
|
||||
void whenGetIsCalled_thenATriggerIsReturned() throws Exception {
|
||||
TriggerDTO expectedTriggerDTO = TriggerUtils.getTriggerInstance("mytrigger");
|
||||
Mockito.when(schedulerService.getTriggerByName("mytrigger")).thenReturn(expectedTriggerDTO);
|
||||
Mockito.when(schedulerService.getLegacyTriggerByName("mytrigger")).thenReturn(expectedTriggerDTO);
|
||||
|
||||
mockMvc.perform(get(TriggerController.TRIGGER_CONTROLLER_BASE_URL + "/mytrigger")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk())
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package it.fabioformosa.quartzmanager.controllers.utils;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.SimpleTriggerInputDTO;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class InvalidSimpleTriggerCommandDTOProvider implements ArgumentsProvider {
|
||||
@Override
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
|
||||
return Stream.of(
|
||||
Arguments.of(SimpleTriggerInputDTO.builder().build()),
|
||||
Arguments.of(SimpleTriggerInputDTO.builder().repeatCount(1).build()),
|
||||
Arguments.of(SimpleTriggerInputDTO.builder().repeatInterval(1L).build())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package it.fabioformosa.quartzmanager.controllers.utils;
|
||||
|
||||
import it.fabioformosa.quartzmanager.common.utils.DateUtils;
|
||||
import it.fabioformosa.quartzmanager.dto.JobKeyDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerKeyDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -30,4 +28,50 @@ public class TriggerUtils {
|
||||
.build();
|
||||
}
|
||||
|
||||
static public SimpleTriggerDTO getSimpleTriggerInstance(String triggerName, SimpleTriggerInputDTO simpleTriggerInputDTO){
|
||||
return SimpleTriggerDTO.builder()
|
||||
.description("simple trigger")
|
||||
.repeatCount(simpleTriggerInputDTO.getRepeatCount())
|
||||
.repeatInterval(simpleTriggerInputDTO.getRepeatInterval())
|
||||
.endTime(DateUtils.getHoursFromNow(2L))
|
||||
.finalFireTime(DateUtils.getHoursFromNow(2L))
|
||||
.jobKeyDTO(JobKeyDTO.builder()
|
||||
.group("defaultJobGroup")
|
||||
.name("sampleJob")
|
||||
.build())
|
||||
.mayFireAgain(true)
|
||||
.triggerKeyDTO(TriggerKeyDTO.builder()
|
||||
.group("defaultTriggerGroup")
|
||||
.name(triggerName)
|
||||
.build())
|
||||
.misfireInstruction(1)
|
||||
.nextFireTime(DateUtils.getHoursFromNow(1L))
|
||||
.priority(1)
|
||||
.startTime(DateUtils.fromLocaleDateTimeToDate(LocalDateTime.now()))
|
||||
.build();
|
||||
}
|
||||
|
||||
static public SimpleTriggerDTO getSimpleTriggerInstance(String triggerName){
|
||||
return SimpleTriggerDTO.builder()
|
||||
.description("simple trigger")
|
||||
.repeatCount(2)
|
||||
.repeatInterval(1000L)
|
||||
.endTime(DateUtils.getHoursFromNow(2L))
|
||||
.finalFireTime(DateUtils.getHoursFromNow(2L))
|
||||
.jobKeyDTO(JobKeyDTO.builder()
|
||||
.group("defaultJobGroup")
|
||||
.name("sampleJob")
|
||||
.build())
|
||||
.mayFireAgain(true)
|
||||
.triggerKeyDTO(TriggerKeyDTO.builder()
|
||||
.group("defaultTriggerGroup")
|
||||
.name(triggerName)
|
||||
.build())
|
||||
.misfireInstruction(1)
|
||||
.nextFireTime(DateUtils.getHoursFromNow(1L))
|
||||
.priority(1)
|
||||
.startTime(DateUtils.fromLocaleDateTimeToDate(LocalDateTime.now()))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package it.fabioformosa.quartzmanager.jobs;
|
||||
|
||||
import it.fabioformosa.quartzmanager.jobs.entities.LogRecord;
|
||||
import it.fabioformosa.quartzmanager.jobs.entities.LogRecord.LogType;
|
||||
import org.quartz.JobExecutionContext;
|
||||
|
||||
public class SampleJob extends AbstractLoggingJob {
|
||||
|
||||
@Override
|
||||
public LogRecord doIt(JobExecutionContext jobExecutionContext) {
|
||||
return new LogRecord(LogType.INFO, "Hello!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package it.fabioformosa.quartzmanager.services;
|
||||
|
||||
import it.fabioformosa.quartzmanager.common.utils.DateUtils;
|
||||
import it.fabioformosa.quartzmanager.dto.*;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.MockitoAnnotations.openMocks;
|
||||
|
||||
class SimpleTriggerSchedulerServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private SimpleTriggerSchedulerService simpleSchedulerService;
|
||||
|
||||
@Mock
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Mock
|
||||
private ConversionService conversionService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
openMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenANotExistingTrigger_whenGetSimplerTriggerByNameIsCalled_thenThrowException() throws SchedulerException {
|
||||
String not_existing_trigger = "not_existing_trigger";
|
||||
Mockito.when(scheduler.getTrigger(any())).thenReturn(null);
|
||||
|
||||
Throwable throwable = Assertions.catchThrowable(() -> simpleSchedulerService.getSimpleTriggerByName(not_existing_trigger));
|
||||
Assertions.assertThat(throwable).isInstanceOf(TriggerNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenASimpleTriggerCommandDTO_whenASimpleTriggerIsScheduled_thenATriggerDTOIsReturned() throws SchedulerException, ClassNotFoundException {
|
||||
SimpleTriggerInputDTO triggerInputDTO = SimpleTriggerInputDTO.builder()
|
||||
.startDate(new Date())
|
||||
.repeatInterval(5000L).repeatCount(5)
|
||||
.endDate(DateUtils.getHoursFromNow(1))
|
||||
.build();
|
||||
|
||||
String simpleTriggerName = "simpleTrigger";
|
||||
|
||||
SimpleTriggerDTO expectedTriggerDTO = SimpleTriggerDTO.builder()
|
||||
.startTime(triggerInputDTO.getStartDate())
|
||||
.repeatInterval(1000)
|
||||
.repeatCount(10)
|
||||
.mayFireAgain(true)
|
||||
.finalFireTime(triggerInputDTO.getEndDate())
|
||||
.jobKeyDTO(JobKeyDTO.builder().name("MyJob").build())
|
||||
.misfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW)
|
||||
.triggerKeyDTO(TriggerKeyDTO.builder().name(simpleTriggerName).build())
|
||||
.build();
|
||||
|
||||
Mockito.when(scheduler.scheduleJob(any(), any())).thenReturn(new Date());
|
||||
Mockito.when(conversionService.convert(any(), eq(SimpleTriggerDTO.class))).thenReturn(expectedTriggerDTO);
|
||||
|
||||
SimpleTriggerCommandDTO simpleTriggerCommandDTO = SimpleTriggerCommandDTO.builder()
|
||||
.triggerName(simpleTriggerName)
|
||||
.simpleTriggerInputDTO(triggerInputDTO)
|
||||
.build();
|
||||
SimpleTriggerDTO simpleTrigger = simpleSchedulerService.scheduleSimpleTrigger("it.fabioformosa.quartzmanager.jobs.SampleJob", simpleTriggerCommandDTO);
|
||||
|
||||
Assertions.assertThat(simpleTrigger).isEqualTo(expectedTriggerDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
name: Phil
|
||||
@@ -0,0 +1,18 @@
|
||||
app:
|
||||
name: quartz-manager
|
||||
|
||||
quartz:
|
||||
enabled: true
|
||||
|
||||
job:
|
||||
frequency: 4000
|
||||
repeatCount: 19
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.boot.autoconfigure.security: INFO
|
||||
it.fabioformosa: DEBUG
|
||||
org.quartz: INFO
|
||||
|
||||
quartz-manager:
|
||||
jobClass: it.fabioformosa.quartzmanager.jobs.SampleJob
|
||||
Reference in New Issue
Block a user