From dc081a1bedfd06ae8f050beff0ce61114fe20d7b Mon Sep 17 00:00:00 2001 From: Fabio Formosa Date: Fri, 22 Jun 2018 13:46:23 +0200 Subject: [PATCH] added some javadocs --- .gitignore | 1 + .../configuration/WebSecurityConfigJWT.java | 204 +++++------ .../controllers/AuthenticationController.java | 157 ++++----- .../controllers/ManagerController.java | 46 --- .../controllers/SchedulerController.java | 308 +++++++++-------- .../controllers/SessionController.java | 27 +- .../controllers/UserController.java | 137 ++++---- .../dto/SchedulerConfigParam.java | 48 +-- .../quartzmanager/enums/SchedulerStates.java | 5 + .../exceptions/ResourceConflictException.java | 7 +- .../jobs/AbstractLoggingJob.java | 59 ++-- .../quartzmanager/jobs/MisfireTestJob.java | 26 -- .../jobs/entities/LogRecord.java | 88 ++--- .../jobs/{ => myjobs}/SampleJob.java | 3 +- .../jobs/tests/MisfireTestJob.java | 37 ++ .../quartzmanager/security/TokenHelper.java | 317 +++++++++--------- .../security/model/Authority.java | 104 +++--- .../quartzmanager/security/model/User.java | 264 ++++++++------- .../src/main/resources/logback.xml | 44 +-- 19 files changed, 955 insertions(+), 927 deletions(-) create mode 100644 .gitignore delete mode 100644 quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/ManagerController.java create mode 100644 quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/enums/SchedulerStates.java delete mode 100644 quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/MisfireTestJob.java rename quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/{ => myjobs}/SampleJob.java (76%) create mode 100644 quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/tests/MisfireTestJob.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8fe4fa --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.project diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java index 8f6bf0d..f68f753 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java @@ -1,99 +1,105 @@ -package it.fabioformosa.quartzmanager.configuration; - -import javax.annotation.Resource; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import it.fabioformosa.quartzmanager.security.ComboEntryPoint; -import it.fabioformosa.quartzmanager.security.auth.AuthenticationFailureHandler; -import it.fabioformosa.quartzmanager.security.auth.AuthenticationSuccessHandler; -import it.fabioformosa.quartzmanager.security.auth.LogoutSuccess; -import it.fabioformosa.quartzmanager.security.auth.RestAuthenticationEntryPoint; -import it.fabioformosa.quartzmanager.security.auth.TokenAuthenticationFilter; -import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService; - -//@Configuration -//@EnableGlobalMethodSecurity(prePostEnabled = true) -public class WebSecurityConfigJWT extends WebSecurityConfigurerAdapter { - - @Value("${jwt.cookie}") - private String TOKEN_COOKIE; - - @Autowired - private CustomUserDetailsService jwtUserDetailsService; - - @Autowired - private RestAuthenticationEntryPoint restAuthenticationEntryPoint; - @Resource - private ComboEntryPoint comboEntryPoint; - - @Autowired - private LogoutSuccess logoutSuccess; - - @Autowired - private AuthenticationSuccessHandler authenticationSuccessHandler; - - @Autowired - private AuthenticationFailureHandler authenticationFailureHandler; - - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) - throws Exception { - authenticationManagerBuilder.userDetailsService(jwtUserDetailsService) - .passwordEncoder(passwordEncoder()); - - } - - @Bean - public TokenAuthenticationFilter jwtAuthenticationTokenFilter() throws Exception { - return new TokenAuthenticationFilter(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - // http.csrf().ignoringAntMatchers("/api/login", "/api/signup") - // .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and() - http.cors().and().csrf().disable() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .exceptionHandling().authenticationEntryPoint(comboEntryPoint).and() - .addFilterBefore(jwtAuthenticationTokenFilter(), BasicAuthenticationFilter.class) - .authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/api/login") - .successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler) - .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/api/logout")) - .logoutSuccessHandler(logoutSuccess).deleteCookies(TOKEN_COOKIE); - - } - - @Bean - CorsConfigurationSource corsConfigurationSource() { - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues()); - return source; - } - -} +package it.fabioformosa.quartzmanager.configuration; + +import javax.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import it.fabioformosa.quartzmanager.security.ComboEntryPoint; +import it.fabioformosa.quartzmanager.security.auth.AuthenticationFailureHandler; +import it.fabioformosa.quartzmanager.security.auth.AuthenticationSuccessHandler; +import it.fabioformosa.quartzmanager.security.auth.LogoutSuccess; +import it.fabioformosa.quartzmanager.security.auth.TokenAuthenticationFilter; +import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService; + +/** + * JWT Temporary disabled + * + * @author Fabio.Formosa + * + */ + +//@Configuration +//@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfigJWT extends WebSecurityConfigurerAdapter { + + @Value("${jwt.cookie}") + private String TOKEN_COOKIE; + + @Autowired + private CustomUserDetailsService jwtUserDetailsService; + + // @Autowired + // private RestAuthenticationEntryPoint restAuthenticationEntryPoint; + @Resource + private ComboEntryPoint comboEntryPoint; + + @Autowired + private LogoutSuccess logoutSuccess; + + @Autowired + private AuthenticationSuccessHandler authenticationSuccessHandler; + + @Autowired + private AuthenticationFailureHandler authenticationFailureHandler; + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) + throws Exception { + authenticationManagerBuilder.userDetailsService(jwtUserDetailsService) + .passwordEncoder(passwordEncoder()); + + } + + @Bean + public TokenAuthenticationFilter jwtAuthenticationTokenFilter() throws Exception { + return new TokenAuthenticationFilter(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // http.csrf().ignoringAntMatchers("/api/login", "/api/signup") + // .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and() + http.cors().and().csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + .exceptionHandling().authenticationEntryPoint(comboEntryPoint).and() + .addFilterBefore(jwtAuthenticationTokenFilter(), BasicAuthenticationFilter.class) + .authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/api/login") + .successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler) + .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/api/logout")) + .logoutSuccessHandler(logoutSuccess).deleteCookies(TOKEN_COOKIE); + + } + + @Bean + CorsConfigurationSource corsConfigurationSource() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues()); + return source; + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java index e67162c..e8b5a6d 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java @@ -1,75 +1,82 @@ -package it.fabioformosa.quartzmanager.controllers; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import it.fabioformosa.quartzmanager.security.TokenHelper; -import it.fabioformosa.quartzmanager.security.model.UserTokenState; -import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService; - -//@RestController -//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE ) -public class AuthenticationController { - - static class PasswordChanger { - public String oldPassword; - public String newPassword; - } - - @Autowired - private CustomUserDetailsService userDetailsService; - - @Autowired - TokenHelper tokenHelper; - - @Value("${jwt.expires_in}") - private int EXPIRES_IN; - - @Value("${jwt.cookie}") - private String TOKEN_COOKIE; - - @RequestMapping(value = "/changePassword", method = RequestMethod.POST) - @PreAuthorize("hasRole('USER')") - public ResponseEntity changePassword(@RequestBody PasswordChanger passwordChanger) { - userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword); - Map result = new HashMap<>(); - result.put( "result", "success" ); - return ResponseEntity.accepted().body(result); - } - - @RequestMapping(value = "/refresh", method = RequestMethod.GET) - public ResponseEntity refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) { - - String authToken = tokenHelper.getToken( request ); - if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) { - // TODO check user password last update - String refreshedToken = tokenHelper.refreshToken(authToken); - - Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken ); - authCookie.setPath( "/" ); - authCookie.setHttpOnly( true ); - authCookie.setMaxAge( EXPIRES_IN ); - // Add cookie to response - response.addCookie( authCookie ); - - UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN); - return ResponseEntity.ok(userTokenState); - } else { - UserTokenState userTokenState = new UserTokenState(); - return ResponseEntity.accepted().body(userTokenState); - } - } - -} +package it.fabioformosa.quartzmanager.controllers; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import it.fabioformosa.quartzmanager.security.TokenHelper; +import it.fabioformosa.quartzmanager.security.model.UserTokenState; +import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService; + +/** + * JWT Temporary disabled + * + * @author Fabio.Formosa + * + */ + +//@RestController +//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE ) +public class AuthenticationController { + + static class PasswordChanger { + public String oldPassword; + public String newPassword; + } + + @Autowired + private CustomUserDetailsService userDetailsService; + + @Autowired + TokenHelper tokenHelper; + + @Value("${jwt.expires_in}") + private int EXPIRES_IN; + + @Value("${jwt.cookie}") + private String TOKEN_COOKIE; + + @RequestMapping(value = "/changePassword", method = RequestMethod.POST) + @PreAuthorize("hasRole('USER')") + public ResponseEntity changePassword(@RequestBody PasswordChanger passwordChanger) { + userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword); + Map result = new HashMap<>(); + result.put( "result", "success" ); + return ResponseEntity.accepted().body(result); + } + + @RequestMapping(value = "/refresh", method = RequestMethod.GET) + public ResponseEntity refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) { + + String authToken = tokenHelper.getToken( request ); + if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) { + // TODO check user password last update + String refreshedToken = tokenHelper.refreshToken(authToken); + + Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken ); + authCookie.setPath( "/" ); + authCookie.setHttpOnly( true ); + authCookie.setMaxAge( EXPIRES_IN ); + // Add cookie to response + response.addCookie( authCookie ); + + UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN); + return ResponseEntity.ok(userTokenState); + } else { + UserTokenState userTokenState = new UserTokenState(); + return ResponseEntity.accepted().body(userTokenState); + } + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/ManagerController.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/ManagerController.java deleted file mode 100644 index b17ebe2..0000000 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/ManagerController.java +++ /dev/null @@ -1,46 +0,0 @@ -package it.fabioformosa.quartzmanager.controllers; - -import javax.annotation.Resource; - -import org.quartz.Scheduler; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.ModelAndView; - -@Controller -@RequestMapping("/manager") -public class ManagerController { - - public enum SchedulerStates { - RUNNING, STOPPED, PAUSED - } - - @Resource - private Scheduler scheduler; - - @RequestMapping - public ModelAndView getPanelView() throws SchedulerException { - ModelAndView mav = new ModelAndView("panelView"); - - 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(); - - mav.addObject("schedulerState", schedulerState.toLowerCase()); - - return mav; - } - - // @MessageMapping("/updates") - // @SendTo("/topic/greetings") - // public String greeting(String message) throws Exception { - // Thread.sleep(3000); // simulated delay - // return "Hello"; - // } - -} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SchedulerController.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SchedulerController.java index aaecc79..d3523a8 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SchedulerController.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SchedulerController.java @@ -1,156 +1,152 @@ -package it.fabioformosa.quartzmanager.controllers; - -import java.util.Collections; -import java.util.Map; - -import javax.annotation.Resource; - -import org.quartz.DailyTimeIntervalTrigger; -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.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import it.fabioformosa.quartzmanager.controllers.ManagerController.SchedulerStates; -import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam; -import it.fabioformosa.quartzmanager.dto.TriggerProgress; -import it.fabioformosa.quartzmanager.scheduler.TriggerMonitor; - -@RestController -@RequestMapping("/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); - - @Resource - private Scheduler scheduler; - - @Resource - private TriggerMonitor triggerMonitor; - - @RequestMapping(value = "/config", method = RequestMethod.GET) - public SchedulerConfigParam getConfig() { - SchedulerConfigParam config = new SchedulerConfigParam(); - - int maxCount = 0; - long repeatIntervalInMills = 0; - if (triggerMonitor.getTrigger() instanceof SimpleTrigger) { - SimpleTrigger simpleTrigger = (SimpleTrigger) triggerMonitor.getTrigger(); - maxCount = simpleTrigger.getRepeatCount() + 1; - repeatIntervalInMills = fromTriggerPerDayToMillSecInterval(simpleTrigger.getRepeatInterval()); - } else if (triggerMonitor.getTrigger() instanceof DailyTimeIntervalTrigger) { - DailyTimeIntervalTrigger dailyTimeIntervalTrigger = (DailyTimeIntervalTrigger) triggerMonitor - .getTrigger(); - maxCount = dailyTimeIntervalTrigger.getRepeatCount() + 1; - repeatIntervalInMills = fromTriggerPerDayToSecInterval( - dailyTimeIntervalTrigger.getRepeatInterval()); - } - - config.setMaxCount(maxCount); - config.setTriggerPerDay(repeatIntervalInMills); - return config; - } - - @RequestMapping("/progress") - public TriggerProgress getProgressInfo() throws SchedulerException { - - SimpleTriggerImpl jobTrigger = (SimpleTriggerImpl) scheduler - .getTrigger(triggerMonitor.getTrigger().getKey()); - - TriggerProgress progress = new TriggerProgress(); - 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 getStatus() throws SchedulerException { - 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()); - } - - @RequestMapping("/pause") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void pause() throws SchedulerException { - scheduler.standby(); - } - - @RequestMapping(value = "/config", method = RequestMethod.POST) - public SchedulerConfigParam postConfig(@RequestBody SchedulerConfigParam config) - throws SchedulerException { - - SimpleTrigger trigger = (SimpleTrigger) triggerMonitor.getTrigger(); - TriggerBuilder triggerBuilder = trigger.getTriggerBuilder(); - - int intervalInSeconds = fromTriggerPerDayToMillSecInterval(config.getTriggerPerDay()); - Trigger newTrigger = triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule() - .withIntervalInMilliseconds(intervalInSeconds).withRepeatCount(config.getMaxCount() - 1)) - .build(); - - scheduler.rescheduleJob(triggerMonitor.getTrigger().getKey(), newTrigger); - triggerMonitor.setTrigger(newTrigger); - return config; - } - - @RequestMapping("/resume") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void resume() throws SchedulerException { - scheduler.start(); - } - - @RequestMapping("/run") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void run() throws SchedulerException { - log.info("Starting scheduler..."); - scheduler.start(); - } - - @ResponseStatus(HttpStatus.NO_CONTENT) - @RequestMapping("/stop") - public void stop() throws SchedulerException { - log.info("Stopping scheduler..."); - scheduler.shutdown(true); - } - - @SuppressWarnings("unused") - private long fromMillsIntervalToTriggerPerDay(long repeatIntervalInMills) { - return (int) Math.ceil(MILLS_IN_A_DAY / repeatIntervalInMills); - } - - private int fromTriggerPerDayToMillSecInterval(long triggerPerDay) { - return (int) Math.ceil(Long.valueOf(MILLS_IN_A_DAY) / triggerPerDay); //with ceil the triggerPerDay is a max value - } - - private int fromTriggerPerDayToSecInterval(long triggerPerDay) { - return (int) Math.ceil(Long.valueOf(SEC_IN_A_DAY) / triggerPerDay); - } - -} +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam; +import it.fabioformosa.quartzmanager.dto.TriggerProgress; +import it.fabioformosa.quartzmanager.enums.SchedulerStates; +import it.fabioformosa.quartzmanager.scheduler.TriggerMonitor; + +/** + * 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("/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); + + @Resource + private Scheduler scheduler; + + @Resource + private TriggerMonitor triggerMonitor; + + @RequestMapping(value = "/config", method = RequestMethod.GET) + public SchedulerConfigParam getConfig() { + log.debug("SCHEDULER - GET CONFIG params"); + SimpleTrigger simpleTrigger = (SimpleTrigger) triggerMonitor.getTrigger(); + + int maxCount = simpleTrigger.getRepeatCount() + 1; + long triggersPerDay = fromMillsIntervalToTriggerPerDay(simpleTrigger.getRepeatInterval()); + + return new SchedulerConfigParam(triggersPerDay, maxCount); + } + + @RequestMapping("/progress") + public TriggerProgress getProgressInfo() throws SchedulerException { + log.trace("SCHEDULER - GET PROGRESS INFO"); + TriggerProgress progress = new TriggerProgress(); + + 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 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()); + } + + @RequestMapping("/pause") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void pause() throws SchedulerException { + log.info("SCHEDULER - PAUSE COMMAND"); + scheduler.standby(); + } + + @RequestMapping(value = "/config", method = RequestMethod.POST) + public SchedulerConfigParam postConfig(@RequestBody SchedulerConfigParam config) throws SchedulerException { + log.info("SCHEDULER - NEW CONFIG {}", config); + SimpleTrigger trigger = (SimpleTrigger) triggerMonitor.getTrigger(); + + TriggerBuilder triggerBuilder = trigger.getTriggerBuilder(); + + int intervalInMills = fromTriggerPerDayToMillsInterval(config.getTriggerPerDay()); + Trigger newTrigger = triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule() + .withIntervalInMilliseconds(intervalInMills).withRepeatCount(config.getMaxCount() - 1)).build(); + + scheduler.rescheduleJob(triggerMonitor.getTrigger().getKey(), newTrigger); + triggerMonitor.setTrigger(newTrigger); + return config; + } + + @RequestMapping("/resume") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void resume() throws SchedulerException { + log.info("SCHEDULER - RESUME COMMAND"); + scheduler.start(); + } + + @RequestMapping("/run") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void run() throws SchedulerException { + log.info("SCHEDULER - START COMMAND"); + scheduler.start(); + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @RequestMapping("/stop") + public void stop() throws SchedulerException { + log.info("SCHEDULER - STOP COMMAND"); + scheduler.shutdown(true); + } + + private long fromMillsIntervalToTriggerPerDay(long repeatIntervalInMills) { + return (int) Math.ceil(MILLS_IN_A_DAY / repeatIntervalInMills); + } + + private int fromTriggerPerDayToMillsInterval(long triggerPerDay) { + return (int) Math.ceil(Long.valueOf(MILLS_IN_A_DAY) / triggerPerDay); // with ceil the triggerPerDay is a max value + } + + @SuppressWarnings("unused") + private int fromTriggerPerDayToSecInterval(long triggerPerDay) { + return (int) Math.ceil(Long.valueOf(SEC_IN_A_DAY) / triggerPerDay); + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SessionController.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SessionController.java index 757e6e3..65dbf54 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SessionController.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/SessionController.java @@ -10,25 +10,26 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; @Controller @RequestMapping("/session") public class SessionController { - private final Logger log = LoggerFactory.getLogger(SessionController.class); + private final Logger log = LoggerFactory.getLogger(SessionController.class); - @RequestMapping("/invalidate") - @PreAuthorize("hasAuthority('ADMIN')") - public String invalidateSession(HttpSession session) { - session.invalidate(); - log.info("Invalidated current session!"); - return "redirect:/manager"; - } + @RequestMapping("/invalidate") + @PreAuthorize("hasAuthority('ADMIN')") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void invalidateSession(HttpSession session) { + session.invalidate(); + log.info("Invalidated current session!"); + } - @RequestMapping("/refresh") - @PreAuthorize("hasAuthority('ADMIN')") - public HttpEntity refreshSession(HttpSession session) { - return new ResponseEntity<>(HttpStatus.OK); - } + @RequestMapping("/refresh") + @PreAuthorize("hasAuthority('ADMIN')") + public HttpEntity refreshSession(HttpSession session) { + return new ResponseEntity<>(HttpStatus.OK); + } } diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java index 819a76a..183324b 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java @@ -1,65 +1,72 @@ -package it.fabioformosa.quartzmanager.controllers; - -import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE) -public class UserController { - - // @Autowired - // private UserService userService; - - - // @RequestMapping(method = POST, value = "/signup") - // public ResponseEntity addUser(@RequestBody UserRequest userRequest, - // UriComponentsBuilder ucBuilder) { - // - // User existUser = this.userService.findByUsername(userRequest.getUsername()); - // if (existUser != null) - // throw new ResourceConflictException(userRequest.getId(), "Username already exists"); - // User user = this.userService.save(userRequest); - // HttpHeaders headers = new HttpHeaders(); - // headers.setLocation(ucBuilder.path("/api/user/{userId}").buildAndExpand(user.getId()).toUri()); - // return new ResponseEntity<>(user, HttpStatus.CREATED); - // } - // - // @RequestMapping(method = GET, value = "/user/all") - // public List loadAll() { - // return this.userService.findAll(); - // } - // - // @RequestMapping(method = GET, value = "/user/{userId}") - // public User loadById(@PathVariable Long userId) { - // return this.userService.findById(userId); - // } - // - // - // @RequestMapping(method = GET, value = "/user/reset-credentials") - // public ResponseEntity resetCredentials() { - // this.userService.resetCredentials(); - // Map result = new HashMap<>(); - // result.put("result", "success"); - // return ResponseEntity.accepted().body(result); - // } - - /* - * We are not using userService.findByUsername here(we could), so it is good that we are making - * sure that the user has role "ROLE_USER" to access this endpoint. - */ - // @RequestMapping("/whoami") - // // @PreAuthorize("hasRole('USER')") - // public User user() { - // return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - // } - - @RequestMapping("/whoami") - @PreAuthorize("isAuthenticated()") - public Object user() { - return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - } - -} +package it.fabioformosa.quartzmanager.controllers; + +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE) +public class UserController { + + /** + * JWT Temporary disabled + * + * @author Fabio.Formosa + * + */ + + // @Autowired + // private UserService userService; + + + // @RequestMapping(method = POST, value = "/signup") + // public ResponseEntity addUser(@RequestBody UserRequest userRequest, + // UriComponentsBuilder ucBuilder) { + // + // User existUser = this.userService.findByUsername(userRequest.getUsername()); + // if (existUser != null) + // throw new ResourceConflictException(userRequest.getId(), "Username already exists"); + // User user = this.userService.save(userRequest); + // HttpHeaders headers = new HttpHeaders(); + // headers.setLocation(ucBuilder.path("/api/user/{userId}").buildAndExpand(user.getId()).toUri()); + // return new ResponseEntity<>(user, HttpStatus.CREATED); + // } + // + // @RequestMapping(method = GET, value = "/user/all") + // public List loadAll() { + // return this.userService.findAll(); + // } + // + // @RequestMapping(method = GET, value = "/user/{userId}") + // public User loadById(@PathVariable Long userId) { + // return this.userService.findById(userId); + // } + // + // + // @RequestMapping(method = GET, value = "/user/reset-credentials") + // public ResponseEntity resetCredentials() { + // this.userService.resetCredentials(); + // Map result = new HashMap<>(); + // result.put("result", "success"); + // return ResponseEntity.accepted().body(result); + // } + + /* + * We are not using userService.findByUsername here(we could), so it is good that we are making + * sure that the user has role "ROLE_USER" to access this endpoint. + */ + // @RequestMapping("/whoami") + // // @PreAuthorize("hasRole('USER')") + // public User user() { + // return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + // } + + @RequestMapping("/whoami") + @PreAuthorize("isAuthenticated()") + public Object user() { + return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/dto/SchedulerConfigParam.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/dto/SchedulerConfigParam.java index f04a7d7..8caf0d1 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/dto/SchedulerConfigParam.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/dto/SchedulerConfigParam.java @@ -2,29 +2,39 @@ package it.fabioformosa.quartzmanager.dto; public class SchedulerConfigParam { - public long triggerPerDay; - public int maxCount; + public long triggerPerDay; + public int maxCount; - public int getMaxCount() { - return maxCount; - } + public SchedulerConfigParam() { + super(); + } - public long getTriggerPerDay() { - return triggerPerDay; - } + public SchedulerConfigParam(long triggerPerDay, int maxCount) { + super(); + this.triggerPerDay = triggerPerDay; + this.maxCount = maxCount; + } - public void setMaxCount(int maxCount) { - this.maxCount = maxCount; - } + public int getMaxCount() { + return maxCount; + } - public void setTriggerPerDay(long triggerPerDay) { - this.triggerPerDay = triggerPerDay; - } + public long getTriggerPerDay() { + return triggerPerDay; + } - @Override - public String toString() { - return "SchedulerConfigParam [triggerPerDay=" + triggerPerDay - + ", maxCount=" + maxCount + "]"; - } + 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 + "]"; + } } diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/enums/SchedulerStates.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/enums/SchedulerStates.java new file mode 100644 index 0000000..f248106 --- /dev/null +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/enums/SchedulerStates.java @@ -0,0 +1,5 @@ +package it.fabioformosa.quartzmanager.enums; + +public enum SchedulerStates { + RUNNING, STOPPED, PAUSED +} \ No newline at end of file diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/exceptions/ResourceConflictException.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/exceptions/ResourceConflictException.java index 1fd5470..a5af1fe 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/exceptions/ResourceConflictException.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/exceptions/ResourceConflictException.java @@ -1,15 +1,14 @@ package it.fabioformosa.quartzmanager.exceptions; public class ResourceConflictException extends RuntimeException { - /** - * - */ + private static final long serialVersionUID = 1791564636123821405L; + private Long resourceId; public ResourceConflictException(Long resourceId, String message) { super(message); - this.setResourceId(resourceId); + setResourceId(resourceId); } public Long getResourceId() { diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/AbstractLoggingJob.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/AbstractLoggingJob.java index 5526f1c..0911526 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/AbstractLoggingJob.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/AbstractLoggingJob.java @@ -13,38 +13,45 @@ import org.springframework.messaging.simp.SimpMessageSendingOperations; import it.fabioformosa.quartzmanager.aspects.ProgressUpdater; import it.fabioformosa.quartzmanager.jobs.entities.LogRecord; +/** + * Extends this class to create a job that produces LogRecord to be displayed + * into the GUI panel + * + * @author Fabio.Formosa + * + */ public abstract class AbstractLoggingJob implements Job { - private static final Logger log = LoggerFactory.getLogger(AbstractLoggingJob.class); + private static final Logger log = LoggerFactory.getLogger(AbstractLoggingJob.class); - @Autowired - private SimpMessageSendingOperations messagingTemplate; + @Autowired + private SimpMessageSendingOperations messagingTemplate; - @Resource - private ProgressUpdater progressUpdater; + @Resource + private ProgressUpdater progressUpdater; - /** - * - * @param jobExecutionContext - * @return final log - */ - public abstract LogRecord doIt(JobExecutionContext jobExecutionContext); + /** + * + * @param jobExecutionContext + * @return final log + */ + public abstract LogRecord doIt(JobExecutionContext jobExecutionContext); - @Override - public final void execute(JobExecutionContext jobExecutionContext) { - try { - LogRecord logMsg = doIt(jobExecutionContext); - logAndSend(logMsg); - progressUpdater.update(); - } catch (SchedulerException e) { - log.error("Error updating progress " + e.getMessage()); - } - } + @Override + public final void execute(JobExecutionContext jobExecutionContext) { + try { + LogRecord logMsg = doIt(jobExecutionContext); + logAndSend(logMsg); + progressUpdater.update(); + } catch (SchedulerException e) { + log.error("Error updating progress " + e.getMessage()); + } + } - public void logAndSend(LogRecord logRecord) { - log.info(logRecord.getMessage()); - logRecord.setThreadName(Thread.currentThread().getName()); - messagingTemplate.convertAndSend("/topic/logs", logRecord); - } + public void logAndSend(LogRecord logRecord) { + log.info(logRecord.getMessage()); + logRecord.setThreadName(Thread.currentThread().getName()); + messagingTemplate.convertAndSend("/topic/logs", logRecord); + } } \ No newline at end of file diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/MisfireTestJob.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/MisfireTestJob.java deleted file mode 100644 index 8e22ddc..0000000 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/MisfireTestJob.java +++ /dev/null @@ -1,26 +0,0 @@ -package it.fabioformosa.quartzmanager.jobs; - -import org.quartz.JobExecutionContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import it.fabioformosa.quartzmanager.jobs.entities.LogRecord; -import it.fabioformosa.quartzmanager.jobs.entities.LogRecord.LogType; - -public class MisfireTestJob extends AbstractLoggingJob { - - private Logger log = LoggerFactory.getLogger(MisfireTestJob.class); - - @Override - public LogRecord doIt(JobExecutionContext jobExecutionContext) { - try { - log.info("{} is going to sleep...", Thread.currentThread().getName()); - Thread.sleep(10 * 1000); - log.info("{} woke up!", Thread.currentThread().getName()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return new LogRecord(LogType.INFO, "Hello!"); - } - -} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/entities/LogRecord.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/entities/LogRecord.java index d4aaba8..912cbf3 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/entities/LogRecord.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/entities/LogRecord.java @@ -2,60 +2,66 @@ package it.fabioformosa.quartzmanager.jobs.entities; import java.util.Date; +/** + * Log record produced by a job at the end of each run + * + * @author Fabio.Formosa + * + */ public class LogRecord { - public enum LogType { - INFO, WARN, ERROR; - } + public enum LogType { + INFO, WARN, ERROR; + } - private Date date; - private LogType type; + private Date date; + private LogType type; - private String message; - private String threadName; + private String message; + private String threadName; - public LogRecord(LogType type, String msg) { - super(); - this.type = type; - message = msg; - date = new Date(); - } + public LogRecord(LogType type, String msg) { + super(); + this.type = type; + message = msg; + date = new Date(); + } - public Date getDate() { - return date; - } + public Date getDate() { + return date; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public String getThreadName() { - return threadName; - } + public String getThreadName() { + return threadName; + } - public LogType getType() { - return type; - } + public LogType getType() { + return type; + } - public void setDate(Date date) { - this.date = date; - } + public void setDate(Date date) { + this.date = date; + } - public void setMessage(String msg) { - message = msg; - } + public void setMessage(String msg) { + message = msg; + } - public void setThreadName(String threadName) { - this.threadName = threadName; - } + public void setThreadName(String threadName) { + this.threadName = threadName; + } - public void setType(LogType type) { - this.type = type; - } + public void setType(LogType type) { + this.type = type; + } - @Override - public String toString() { - return "LogRecord [date=" + date + ", type=" + type + ", message=" + message + "]"; - } + @Override + public String toString() { + return "LogRecord [date=" + date + ", type=" + type + ", message=" + message + "]"; + } } diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/SampleJob.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/myjobs/SampleJob.java similarity index 76% rename from quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/SampleJob.java rename to quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/myjobs/SampleJob.java index 3cd40f0..a6e032c 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/SampleJob.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/myjobs/SampleJob.java @@ -1,7 +1,8 @@ -package it.fabioformosa.quartzmanager.jobs; +package it.fabioformosa.quartzmanager.jobs.myjobs; import org.quartz.JobExecutionContext; +import it.fabioformosa.quartzmanager.jobs.AbstractLoggingJob; import it.fabioformosa.quartzmanager.jobs.entities.LogRecord; import it.fabioformosa.quartzmanager.jobs.entities.LogRecord.LogType; diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/tests/MisfireTestJob.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/tests/MisfireTestJob.java new file mode 100644 index 0000000..88c30b9 --- /dev/null +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/jobs/tests/MisfireTestJob.java @@ -0,0 +1,37 @@ +package it.fabioformosa.quartzmanager.jobs.tests; + +import org.quartz.JobExecutionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import it.fabioformosa.quartzmanager.jobs.AbstractLoggingJob; +import it.fabioformosa.quartzmanager.jobs.entities.LogRecord; +import it.fabioformosa.quartzmanager.jobs.entities.LogRecord.LogType; + +/** + * This job can be used to test the misfire policy. It pretends to be a long + * processing job (sleeping for a while) + * + * @author Fabio.Formosa + * + */ +public class MisfireTestJob extends AbstractLoggingJob { + + private Logger log = LoggerFactory.getLogger(MisfireTestJob.class); + + @Override + public LogRecord doIt(JobExecutionContext jobExecutionContext) { + try { + log.info("{} is going to sleep...", Thread.currentThread().getName()); + + Thread.sleep(10 * 1000); + + log.info("{} woke up!", Thread.currentThread().getName()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return new LogRecord(LogType.INFO, "Hello!"); + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/TokenHelper.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/TokenHelper.java index 0695574..0331f76 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/TokenHelper.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/TokenHelper.java @@ -1,156 +1,161 @@ -package it.fabioformosa.quartzmanager.security; - -import java.util.Date; -import java.util.Map; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; - -import org.joda.time.DateTime; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; - - -//@Component -public class TokenHelper { - - @Value("${app.name}") - private String APP_NAME; - - @Value("${jwt.secret}") - private String SECRET; - - @Value("${jwt.expires_in}") - private int EXPIRES_IN; - - @Value("${jwt.header}") - private String AUTH_HEADER; - - @Value("${jwt.cookie}") - private String AUTH_COOKIE; - - @Autowired - UserDetailsService userDetailsService; - - private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512; - - public Boolean canTokenBeRefreshed(String token) { - try { - final Date expirationDate = getClaimsFromToken(token).getExpiration(); - String username = getUsernameFromToken(token); - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - return expirationDate.compareTo(generateCurrentDate()) > 0; - } catch (Exception e) { - return false; - } - } - - public String generateToken(String username) { - return Jwts.builder() - .setIssuer( APP_NAME ) - .setSubject(username) - .setIssuedAt(generateCurrentDate()) - .setExpiration(generateExpirationDate()) - .signWith( SIGNATURE_ALGORITHM, SECRET ) - .compact(); - } - - /** - * Find a specific HTTP cookie in a request. - * - * @param request - * The HTTP request object. - * @param name - * The cookie name to look for. - * @return The cookie, or null if not found. - */ - public Cookie getCookieValueByName(HttpServletRequest request, String name) { - if (request.getCookies() == null) - return null; - for (int i = 0; i < request.getCookies().length; i++) - if (request.getCookies()[i].getName().equals(name)) - return request.getCookies()[i]; - return null; - } - - public String getToken( HttpServletRequest request ) { - /** - * Getting the token from Cookie store - */ - Cookie authCookie = getCookieValueByName( request, AUTH_COOKIE ); - if ( authCookie != null ) - return authCookie.getValue(); - /** - * Getting the token from Authentication header - * e.g Bearer your_token - */ - String authHeader = request.getHeader(AUTH_HEADER); - if ( authHeader != null && authHeader.startsWith("Bearer ")) - return authHeader.substring(7); - - return null; - } - - public String getUsernameFromToken(String token) { - String username; - try { - final Claims claims = getClaimsFromToken(token); - username = claims.getSubject(); - } catch (Exception e) { - username = null; - } - return username; - } - - public String refreshToken(String token) { - String refreshedToken; - try { - final Claims claims = getClaimsFromToken(token); - claims.setIssuedAt(generateCurrentDate()); - refreshedToken = generateToken(claims); - } catch (Exception e) { - refreshedToken = null; - } - return refreshedToken; - } - - private Date generateCurrentDate() { - return new Date(getCurrentTimeMillis()); - } - - private Date generateExpirationDate() { - - return new Date(getCurrentTimeMillis() + this.EXPIRES_IN * 1000); - } - - private Claims getClaimsFromToken(String token) { - Claims claims; - try { - claims = Jwts.parser() - .setSigningKey(this.SECRET) - .parseClaimsJws(token) - .getBody(); - } catch (Exception e) { - claims = null; - } - return claims; - } - - private long getCurrentTimeMillis() { - return DateTime.now().getMillis(); - } - - String generateToken(Map claims) { - return Jwts.builder() - .setClaims(claims) - .setExpiration(generateExpirationDate()) - .signWith( SIGNATURE_ALGORITHM, SECRET ) - .compact(); - } -} +package it.fabioformosa.quartzmanager.security; + +import java.util.Date; +import java.util.Map; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + +import org.joda.time.DateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetailsService; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +/** + * JWT Temporary disabled + * + * @author Fabio.Formosa + * + */ + +//@Component +public class TokenHelper { + + @Value("${app.name}") + private String APP_NAME; + + @Value("${jwt.secret}") + private String SECRET; + + @Value("${jwt.expires_in}") + private int EXPIRES_IN; + + @Value("${jwt.header}") + private String AUTH_HEADER; + + @Value("${jwt.cookie}") + private String AUTH_COOKIE; + + @Autowired + UserDetailsService userDetailsService; + + private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512; + + public Boolean canTokenBeRefreshed(String token) { + try { + final Date expirationDate = getClaimsFromToken(token).getExpiration(); + // String username = getUsernameFromToken(token); + // UserDetails userDetails = userDetailsService.loadUserByUsername(username); + return expirationDate.compareTo(generateCurrentDate()) > 0; + } catch (Exception e) { + return false; + } + } + + public String generateToken(String username) { + return Jwts.builder() + .setIssuer( APP_NAME ) + .setSubject(username) + .setIssuedAt(generateCurrentDate()) + .setExpiration(generateExpirationDate()) + .signWith( SIGNATURE_ALGORITHM, SECRET ) + .compact(); + } + + /** + * Find a specific HTTP cookie in a request. + * + * @param request + * The HTTP request object. + * @param name + * The cookie name to look for. + * @return The cookie, or null if not found. + */ + public Cookie getCookieValueByName(HttpServletRequest request, String name) { + if (request.getCookies() == null) + return null; + for (int i = 0; i < request.getCookies().length; i++) + if (request.getCookies()[i].getName().equals(name)) + return request.getCookies()[i]; + return null; + } + + public String getToken( HttpServletRequest request ) { + /** + * Getting the token from Cookie store + */ + Cookie authCookie = getCookieValueByName( request, AUTH_COOKIE ); + if ( authCookie != null ) + return authCookie.getValue(); + /** + * Getting the token from Authentication header + * e.g Bearer your_token + */ + String authHeader = request.getHeader(AUTH_HEADER); + if ( authHeader != null && authHeader.startsWith("Bearer ")) + return authHeader.substring(7); + + return null; + } + + public String getUsernameFromToken(String token) { + String username; + try { + final Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + public String refreshToken(String token) { + String refreshedToken; + try { + final Claims claims = getClaimsFromToken(token); + claims.setIssuedAt(generateCurrentDate()); + refreshedToken = generateToken(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + private Date generateCurrentDate() { + return new Date(getCurrentTimeMillis()); + } + + private Date generateExpirationDate() { + + return new Date(getCurrentTimeMillis() + EXPIRES_IN * 1000); + } + + private Claims getClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser() + .setSigningKey(SECRET) + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + claims = null; + } + return claims; + } + + private long getCurrentTimeMillis() { + return DateTime.now().getMillis(); + } + + String generateToken(Map claims) { + return Jwts.builder() + .setClaims(claims) + .setExpiration(generateExpirationDate()) + .signWith( SIGNATURE_ALGORITHM, SECRET ) + .compact(); + } +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/Authority.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/Authority.java index 0b37f72..88e7826 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/Authority.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/Authority.java @@ -1,49 +1,55 @@ -package it.fabioformosa.quartzmanager.security.model; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -import org.springframework.security.core.GrantedAuthority; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -@Entity -@Table(name="Authority") -public class Authority implements GrantedAuthority { - - @Id - @Column(name="id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - Long id; - - @Column(name="name") - String name; - - @Override - public String getAuthority() { - return name; - } - - @JsonIgnore - public Long getId() { - return id; - } - - @JsonIgnore - public String getName() { - return name; - } - - public void setId(Long id) { - this.id = id; - } - - public void setName(String name) { - this.name = name; - } - -} +package it.fabioformosa.quartzmanager.security.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.springframework.security.core.GrantedAuthority; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * Temporary enabled only inMemoryAuthentication + * + * @author Fabio.Formosa + * + */ +@Entity +@Table(name="Authority") +public class Authority implements GrantedAuthority { + + @Id + @Column(name="id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + @Column(name="name") + String name; + + @Override + public String getAuthority() { + return name; + } + + @JsonIgnore + public Long getId() { + return id; + } + + @JsonIgnore + public String getName() { + return name; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/User.java b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/User.java index 29d7467..f2d16bb 100644 --- a/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/User.java +++ b/quartz-manager-backend/src/main/java/it/fabioformosa/quartzmanager/security/model/User.java @@ -1,129 +1,135 @@ -package it.fabioformosa.quartzmanager.security.model; - -import java.io.Serializable; -import java.util.Collection; -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -@Entity -@Table(name = "USER") -public class User implements UserDetails, Serializable { - @Id - @Column(name = "id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "username") - private String username; - - @JsonIgnore - @Column(name = "password") - private String password; - - @Column(name = "firstname") - private String firstname; - - @Column(name = "lastname") - private String lastname; - - - @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinTable(name = "user_authority", - joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id")) - private List authorities; - - @Override - public Collection getAuthorities() { - return this.authorities; - } - - public String getFirstname() { - return firstname; - } - - public Long getId() { - return id; - } - - public String getLastname() { - return lastname; - } - - @Override - public String getPassword() { - return password; - } - - @Override - public String getUsername() { - return username; - } - - // We can add the below fields in the users table. - // For now, they are hardcoded. - @JsonIgnore - @Override - public boolean isAccountNonExpired() { - return true; - } - - @JsonIgnore - @Override - public boolean isAccountNonLocked() { - return true; - } - - @JsonIgnore - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @JsonIgnore - @Override - public boolean isEnabled() { - return true; - } - - public void setAuthorities(List authorities) { - this.authorities = authorities; - } - - public void setFirstname(String firstname) { - this.firstname = firstname; - } - - public void setId(Long id) { - this.id = id; - } - - public void setLastname(String lastname) { - - this.lastname = lastname; - } - - public void setPassword(String password) { - this.password = password; - } - - public void setUsername(String username) { - this.username = username; - } -} +package it.fabioformosa.quartzmanager.security.model; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * Temporary enabled only inMemoryAuthentication + * + * @author Fabio.Formosa + * + */ +@Entity +@Table(name = "USER") +public class User implements UserDetails, Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "username") + private String username; + + @JsonIgnore + @Column(name = "password") + private String password; + + @Column(name = "firstname") + private String firstname; + + @Column(name = "lastname") + private String lastname; + + + @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinTable(name = "user_authority", + joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id")) + private List authorities; + + @Override + public Collection getAuthorities() { + return authorities; + } + + public String getFirstname() { + return firstname; + } + + public Long getId() { + return id; + } + + public String getLastname() { + return lastname; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + // We can add the below fields in the users table. + // For now, they are hardcoded. + @JsonIgnore + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isEnabled() { + return true; + } + + public void setAuthorities(List authorities) { + this.authorities = authorities; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public void setId(Long id) { + this.id = id; + } + + public void setLastname(String lastname) { + + this.lastname = lastname; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/quartz-manager-backend/src/main/resources/logback.xml b/quartz-manager-backend/src/main/resources/logback.xml index 57c6252..78004b6 100644 --- a/quartz-manager-backend/src/main/resources/logback.xml +++ b/quartz-manager-backend/src/main/resources/logback.xml @@ -1,23 +1,23 @@ - - - - - - - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - - - - - + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%.7thread] %-5level [%-40.40logger{49}:%-3L] --- %m%n + + + + + + + + + + + + + + + \ No newline at end of file