package io.robe.quartz;
import io.dropwizard.Configuration;
import io.dropwizard.ConfiguredBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.robe.quartz.configuration.HasQuartzConfiguration;
import io.robe.quartz.configuration.QuartzConfiguration;
import io.robe.quartz.info.JobInfo;
import io.robe.quartz.info.JobInfoProvider;
import io.robe.quartz.info.TriggerInfo;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Configures Quartz.
* Collect {@link JobInfoProvider} classes
* Initializes scheduler
* Collects all subtypes of {@link org.quartz.Job} annotated with {@link RobeJob} including {@link @RobeTrigger}'s
* * Collects additional triggers from providers
* * Registers them all for future control.
* Holds application start and end triggered jobs for managed access.
* Provides Job & Trigger Registery
*/
public class QuartzBundle<T extends Configuration & HasQuartzConfiguration> implements ConfiguredBundle<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzBundle.class);
private Set<JobDetail> onStartJobs = null;
private Set<JobDetail> onStopJobs = null;
public static final ConcurrentHashMap<String, JobInfo> JOBS = new ConcurrentHashMap<>();
public QuartzBundle() {
}
/**
* Initializes the environment. Forwards the configuration to Quartz.
* Collect {@link JobInfoProvider} classes
* Initializes scheduler
* Collects all subtypes of {@link org.quartz.Job} annotated with {@link RobeJob} including {@link @RobeTrigger}'s
* * Collects additional triggers from providers
* * Registers them all for future control.
*
* @param configuration the configuration object
* @param environment the service's {@link io.dropwizard.setup.Environment}
* @throws Exception if something goes wrong
*/
@Override
public void run(T configuration, Environment environment) {
QuartzConfiguration qConf = configuration.getQuartz();
try {
initializeScheduler(qConf.getProperties());
collectAndScheduleJobs(qConf.getScanPackages());
environment.lifecycle().manage(new ManagedQuartz(getOnStartJobs(), getOnStopJobs()));
} catch (SchedulerException e) {
LOGGER.error("SchedulerException:", e);
}
}
/**
* Initialize scheduler and start JobManager
*
* @param properties
* @throws SchedulerException
*/
private void initializeScheduler(Properties properties) throws SchedulerException {
SchedulerFactory factory = new StdSchedulerFactory(properties);
Scheduler scheduler = factory.getScheduler();
scheduler.start();
JobManager.initialize(scheduler);
}
private void collectAndScheduleJobs(String[] packages) throws SchedulerException {
Set<Class<? extends Job>> quartzJobs;
onStartJobs = new HashSet<>();
onStopJobs = new HashSet<>();
for (String pkg : packages) {
LOGGER.info("Scanning Jobs package : " + pkg);
Reflections reflections = new Reflections(pkg);
quartzJobs = reflections.getSubTypesOf(Job.class);
for (Class<? extends Job> clazz : quartzJobs) {
RobeJob infoAnn = clazz.getDeclaredAnnotation(RobeJob.class);
if (infoAnn == null)
continue;
JobInfoProvider infoProvider;
try {
infoProvider = infoAnn.provider().newInstance();
} catch (Exception e) {
e.printStackTrace();
continue;
}
Set<Trigger> triggers = new HashSet<>();
JobInfo info = infoProvider.getJob(clazz);
if (info == null || JOBS.containsKey(info.getJobClass().getName()))
continue;
JobDetail detail = JobInfoProvider.convert2JobDetail(info);
StringBuilder logBuilder = new StringBuilder();
//Collect all triggers
for (TriggerInfo tInfo : info.getTriggers()) {
logBuilder.append("\n\t\tTrigger: ")
.append(clazz.getName())
.append("\tName: ")
.append(tInfo.getName())
.append("\tType:")
.append(tInfo.getType().name());
switch (tInfo.getType()) {
case ON_APP_START:
onStartJobs.add(detail);
break;
case ON_APP_STOP:
onStopJobs.add(detail);
break;
default:
triggers.add(JobInfoProvider.convert2Trigger(tInfo, info));
}
}
LOGGER.info("\n\tClass {} \n\tName: {} \n\tDesc: {} \n\t Triggers: {}",
info.getJobClass().getName(),
info.getName(),
info.getDescription(),
logBuilder.toString()
);
JobManager.getInstance().scheduleJob(detail, triggers, true);
JOBS.put(info.getJobClass().getName(), info);
}
}
}
/**
* Initializes the service bootstrap.
*
* @param bootstrap the service bootstrap
*/
@Override
public void initialize(Bootstrap<?> bootstrap) {
LOGGER.info("Initializing QuartzBundle");
}
public Set<JobDetail> getOnStartJobs() {
return onStartJobs;
}
public Set<JobDetail> getOnStopJobs() {
return onStopJobs;
}
}