| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.epam.datalab.backendapi.schedulers.internal; |
| |
| import com.epam.datalab.backendapi.SelfServiceApplication; |
| import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration; |
| import com.epam.datalab.backendapi.domain.SchedulerConfigurationData; |
| import com.epam.datalab.exceptions.DatalabException; |
| import com.fiestacabin.dropwizard.quartz.GuiceJobFactory; |
| import com.google.inject.Inject; |
| import io.dropwizard.lifecycle.Managed; |
| import lombok.extern.slf4j.Slf4j; |
| import org.quartz.CronScheduleBuilder; |
| import org.quartz.Job; |
| import org.quartz.JobDetail; |
| import org.quartz.Scheduler; |
| import org.quartz.SchedulerException; |
| import org.quartz.Trigger; |
| import org.quartz.TriggerKey; |
| import org.reflections.Reflections; |
| import org.reflections.scanners.SubTypesScanner; |
| |
| import java.util.Optional; |
| |
| import static org.quartz.JobBuilder.newJob; |
| import static org.quartz.TriggerBuilder.newTrigger; |
| |
| @Slf4j |
| public class ManagedScheduler implements Managed { |
| private final Scheduler scheduler; |
| private final GuiceJobFactory jobFactory; |
| private final SelfServiceApplicationConfiguration config; |
| |
| @Inject |
| public ManagedScheduler(Scheduler scheduler, GuiceJobFactory jobFactory, |
| SelfServiceApplicationConfiguration config) { |
| this.scheduler = scheduler; |
| this.jobFactory = jobFactory; |
| this.config = config; |
| } |
| |
| @Override |
| public void start() throws Exception { |
| scheduler.setJobFactory(jobFactory); |
| scheduler.start(); |
| |
| new Reflections(SelfServiceApplication.class.getPackage().getName(), new SubTypesScanner()) |
| .getSubTypesOf(Job.class) |
| .forEach(scheduledClass -> |
| Optional.ofNullable(scheduledClass.getAnnotation(Scheduled.class)) |
| .filter(this::triggerNotExist) |
| .ifPresent(scheduleAnn -> schedule(scheduledClass, scheduleAnn))); |
| |
| } |
| |
| @Override |
| public void stop() throws Exception { |
| scheduler.shutdown(); |
| } |
| |
| private Trigger getTrigger(SchedulerConfigurationData schedulerConfig, String schedulerName) { |
| return newTrigger() |
| .withIdentity(schedulerName) |
| .withSchedule(CronScheduleBuilder.cronSchedule(schedulerConfig.getCron())) |
| .startNow() |
| .build(); |
| } |
| |
| private void schedule(Class<? extends Job> scheduledClass, Scheduled scheduleAnn) { |
| final String schedulerName = scheduleAnn.value(); |
| final SchedulerConfigurationData schedulerConfig = |
| Optional.ofNullable(config.getSchedulers().get(schedulerName)).orElseThrow(() -> new IllegalStateException( |
| "There is no configuration provided for scheduler with name " + schedulerName)); |
| if (schedulerConfig.isEnabled()) { |
| scheduleJob(newJob(scheduledClass).build(), schedulerConfig, scheduleAnn.value()); |
| } |
| } |
| |
| private void scheduleJob(JobDetail job, SchedulerConfigurationData schedulerConfig, String schedulerName) { |
| try { |
| final Trigger trigger = getTrigger(schedulerConfig, schedulerName); |
| scheduler.scheduleJob(job, trigger); |
| log.info("Scheduled job {} with trigger {}", job, trigger); |
| } catch (SchedulerException e) { |
| log.error("Can't schedule job due to: {}", e.getMessage()); |
| throw new DatalabException("Can't schedule job due to: " + e.getMessage(), e); |
| } |
| } |
| |
| private boolean triggerNotExist(Scheduled scheduled) { |
| try { |
| return !scheduler.checkExists(new TriggerKey(scheduled.value())); |
| } catch (SchedulerException e) { |
| log.error("Can not check if trigger exist due to: {}", e.getMessage()); |
| throw new DatalabException("Can not check if trigger exist due to: {}" + e.getMessage(), e); |
| } |
| } |
| } |