Creating a Quartz Plug-In
Creating a new plug-in is very simple. All you have to do is create a Java class (or reuse an existing one) that implements the org.quartz.spi.SchedulerPlugin interface. The Scheduler will create an instance of the plug-in during startup. The plug-in must have a no-argument constructor and obviously not be abstract.
The JobInitializationPlugin
The Quartz framework includes a plug-in for loading job and trigger information from an XML file. The plug-in is org.quartz.plugins.xml.JobInitializationPlugin and was discussed briefly back in Chapter 3, "Hello, Quartz." When you use this plug-in, the Quartz framework searches for a file called quartz_jobs.xml and attempts to load job and trigger information from this file.
As Chapter 3 explained, this plug-in is very convenient when your application requirements don't involve loading job information from a database. It's also very useful during development and testing because you can quickly configure which jobs and triggers are to be fired. That is, arguably, it's easier to modify an XML file than a set of database tables.
A nice extension to this idea of loading job and trigger information from an XML file would be to have a directory where you can store job XML files, and, by using a plug-in, the Scheduler would load whatever job files were present. This would enable you to conveniently add or remove jobs at Scheduler startup by simply adding or removing them from the specified directory. In the rest of this chapter, we show you how to build this plug-in.
Creating the JobLoaderPlugin
We call this new plug-in the JobLoaderPlugin. Listing 8.2 shows the JobLoaderPlugin class.
Listing 8.2. A Quartz SchedulerPlugin that Loads Multiple Job Files from a Directory
package org.cavaness.quartzbook.chapter8; import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; import org.quartz.spi.SchedulerPlugin; import org.quartz.xml.JobSchedulingDataProcessor; public class JobLoaderPlugin implements SchedulerPlugin { private static Log logger = LogFactory.getLog(JobLoaderPlugin.class); // The directory to load jobs from private String jobsDirectory; // An array of File objects private File[] jobFiles = null; private String pluginName; private Scheduler scheduler; private boolean validateXML = true; private boolean validateSchema = true; public JobLoaderPlugin() { } public File[] getJobFiles() { return jobFiles; } public void setJobFiles(File[] jobFiles) { this.jobFiles = jobFiles; } public boolean isValidateSchema() { return validateSchema; } public void setValidateSchema(boolean validatingSchema) { this.validateSchema = validatingSchema; } public void initialize(String name, final Scheduler scheduler) throws SchedulerException { this.pluginName = name; this.scheduler = scheduler; logger.debug("Registering Plugin " + pluginName); // Load the job definitions from the specified directory loadJobs(); } private void loadJobs() throws SchedulerException { File dir = null; // Check directory if (getJobsDirectory() == null || !(dir = new File(getJobsDirectory())).exists()) { throw new SchedulerConfigException( "The jobs directory was missing " + jobsDirectory); } logger.info("Loading jobs from " + dir.getName()); // Only XML files, filtering out any directories this.jobFiles = dir.listFiles(new XMLFileOnlyFilter()); } public void start() { processJobs(); } public void shutdown() { // nothing to clean up } public void processJobs() { // There should be at least one job if (getJobFiles() == null || getJobFiles().length == 0) { return; } JobSchedulingDataProcessor processor = new JobSchedulingDataProcessor( true, isValidateXML(), isValidateSchema()); int size = getJobFiles().length; for (int i = 0; i < size; i++) { File jobFile = getJobFiles()[i]; String fileName = jobFile.getAbsolutePath(); logger.debug("Loading job file: " + fileName); try { processor.processFileAndScheduleJobs( fileName, scheduler, true); } catch (Exception ex) { logger.error("Error loading jobs: " + fileName); logger.error(ex); } } } public String getJobsDirectory() { return jobsDirectory; } public void setJobsDirectory(String jobsDirectory) { this.jobsDirectory = jobsDirectory; } public String getPluginName() { return pluginName; } public void setPluginName(String pluginName) { this.pluginName = pluginName; } public boolean isValidateXML() { return validateXML; } public void setValidateXML(boolean validateXML) { this.validateXML = validateXML; } } |
The real work of the JobLoaderPlugin in Listing 8.2 is done in just two methods: initialize() and start(). Both are required by the SchedulerPlugin interface. The rest of the methods are just setXXX and getXXX methods to fulfill the JavaBean contract because private properties have been declared.
The JobLoaderPlugin initialize() Method
As you can see, the initialize() method, which is called by the Scheduler, calls the private loadJobs() method. The loadJobs() method uses the jobsDirectory that was passed in from the quartz.properties file to retrieve all XML files stored in that directory. The plug-in doesn't try to schedule the jobs yet because the Scheduler isn't fully instantiated when the plug-in's initialize() method is called. The JobLoaderPlugin simply holds on to an array of File objects, waiting for the start() method to be called. We also hold on to the instance of the Scheduler so that we have access to it when the start() method is called.
The JobLoaderPlugin start() Method
When the Scheduler calls the start() method in the JobLoaderPlugin, the start() method calls processJobs(). The processJobs() method loops through the array of job files and loads each one into the Scheduler instance.
The processing of the job file is done by an instance of an org.quartz.xml JobSchedulingDataProcessor. The processFileAndScheduleJobs() method is called and passed the filename, the Scheduler instance, and a Boolean that tells whether existing jobs should be overwritten.
When the processJobs() method is complete, all job files from the specified jobsDirectory should have been loaded and scheduled.
Registering Your Plug Ins
|