You can have as many properties as you need to configure your plug-in.
你可以用多个属性配置插件。
<o:p> </o:p>
The Quartz framework converts the property values to the type specified in the plug-in, assuming that it's a primitive type. For example, you can specify properties of type int and expect Quartz to convert the String from the quartz.properties file to an int. The framework, however, will not convert 1 to an integer class.
<o:p> </o:p>
Quartz会将属性值转换为插件中定义的类型,假定该类型是基本数据类型。例如你可以指定参数为int,Quartz会将quartz.properties中的字符串转换为int值。然而框架不会将1转换为Integer类。
<o:p> </o:p>
Creating the Job File for the JobLoaderPlugin<o:p></o:p>
创建JobLoaderPlugin使用的Job文件<o:p></o:p>
<o:p> </o:p>
The JobLoaderPlugin looks for all XML files in the specified directory and assumes that each file is a valid Quartz jobs file. By "valid," we mean that the XML file adheres to the latest job-scheduling XSD file, which at the time of this writing is job_scheduling_data_1_5.xsd.
<o:p> </o:p>
JobLoaderPlugin在指定的文件夹中查找所有的XML文件并假定这些文件都是合法的Quartz job定义文件。所谓“合法”值XML遵循最新的作业调度XSD文件。在本书编写时最新的版本是job_scheduling_data_1_5.xsd。
<o:p> </o:p>
To make the JobLoaderPlugin more useful, we put each job, along with its job detail and trigger information, in a single XML file. This enables us to add and remove complete jobs just by putting the file into the directory or taking it out. This is very helpful in a development environment when you want to test only certain jobs. A single job XML file is shown in Listing 8.4.
<o:p> </o:p>
为了让JobLoaderPlugin更加有用,我们将每个job与它的job detail、触发器信息单独作为一个XML文件。这使得我们添加移除整个job时候只需要将文件添加或移出文件夹。在开发环境中如果我们需要测试某个单独的job的时候这是非常有帮助的。一个单独的job XML文件如列表8.4。
<o:p> </o:p>
Listing 8.4. A Job XML File Read by the JobLoaderPlugin<o:p></o:p>
列表8.4 供JobLoaderPlugin读取的一个Job XML文件
- <?xml version='1.0' encoding='utf-8'?>
- <quartz xmlns="http://www.opensymphony.com/quartz/JobSchedulingData"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData
- http://www.opensymphony.com/quartz/xml/job_scheduling_data_1_5.xsd"
- version="1.5">
- <job>
- <job-detail>
- <name>PrintInfoJob1</name>
- <group>DEFAULT</group>
- <job-class>
- org.cavaness.quartzbook.chapter3.ScanDirectoryJob
- </job-class>
- <volatility>false</volatility>
- <durability>false</durability>
- <recover>false</recover>
- <job-data-map allows-transient-data="true">
- <entry>
- <key>SCAN_DIR</key>
- <value>c:\quartz-book\input1</value>
- </entry>
- </job-data-map>
- </job-detail>
- <trigger>
- <simple>
- <name>trigger1</name>
- <group>DEFAULT</group>
- <job-name>PrintInfoJob1</job-name>
- <job-group>DEFAULT</job-group>
- <start-time>2005-07-30T16:04:00</start-time>
- <!-- repeat indefinitely every 10 seconds -->
- <repeat-count>-1</repeat-count>
- <repeat-interval>10000</repeat-interval>
- </simple>
- </trigger>
- </job>
- </quartz>
The job file is Listing 8.4 contains all the information necessary for the JobLoaderPlugin to schedule the job. This file also contains an entry for the JobDataMap, which is available to the job class at runtime. The example in Listing 8.4 uses a configured SimpleTrigger to schedule an infinitely repeating trigger that fires every 10 seconds. To further test the plug-in, we created a second job file, which differs from the first in some small way. Listing 8.5 shows the second job file.
<o:p> </o:p>
列表8.4显示的job文件包含所有的供JobLoaderPlugin调度job所需要的信息。这个文件还包含一个可以在类中实时供JobDataMap调用的实体。列表8.4战士的例子使用SimpleTrigger。它频率是没10秒一次,无限循环。为了更进一步测试插件,我们创建第2个job文件,与第一个相比有一些小不同。列表8.5显示了第2个job文件。
<o:p> </o:p>
Listing 8.5. A Second Job XML File Loaded by the JobLoaderPlugin<o:p></o:p>
列表8.5 JobLoaderPlugin加载的第2个job XML文件<o:p></o:p>
- <?xml version='1.0' encoding='utf-8'?>
- <quartz xmlns="http://www.opensymphony.com/quartz/JobSchedulingData"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData
- http://www.opensymphony.com/quartz/xml/job_scheduling_data_1_5.xsd"
- version="1.5">
- <job>
- <job-detail>
- <name>PrintInfoJob2</name>
- <group>DEFAULT</group>
- <job-class>
- org.cavaness.quartzbook.chapter3.ScanDirectoryJob</job-class>
- <volatility>false</volatility>
- <durability>false</durability>
- <recover>false</recover>
- <job-data-map allows-transient-data="true">
- <entry>
- <key>SCAN_DIR</key>
- <value>c:\quartz-book\input2</value>
- </entry>
- </job-data-map>
- </job-detail>
- <trigger>
- <simple>
- <name>trigger2</name>
- <group>DEFAULT</group>
- <job-name>PrintInfoJob2</job-name>
- <job-group>DEFAULT</job-group>
- <start-time>2005-07-30T16:04:00</start-time>
- <!-- repeat indefinitely every 10 seconds -->
- <repeat-count>-1</repeat-count>
- <repeat-interval>60000</repeat-interval>
- </simple>
- </trigger>
- </job>
- </quartz>
The second job file in Listing 8.5 differs only slightly from the one in Listing 8.4. We've changed the directory for the job, which is scanned and changed the trigger schedule. The point here is that you can have multiple jobs in the jobs directory, and the JobLoaderPlugin will load them all and schedule them individually with the Scheduler.
<o:p> </o:p>
列表8.5显示的第2个job文件与8.4显示的第一个相比只有一点不同。我们改变了搜索改变触发调度作业的文件夹。有一点注意的是你可以放多个job文件到文件夹中,JobLoaderPlugin将分别加载并用Scheduler调度他们。(老外就是这样说了好几遍还罗嗦^_^)
<o:p> </o:p>
<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 0.75pt; HEIGHT: 0.75pt" o:button="t" alt="" type="#_x0000_t75"></v:shape>
Using Multiple Plug-Ins<o:p></o:p>
使用多个插件<o:p></o:p>
You can register as many plug-ins in the quartz.properties file as you like. However, the order of loading and initialization can't be guaranteed because Quartz loads all the properties into a map and then loops through the plug-ins in the order that they are retrieved from the map.
<o:p> </o:p>
你可以在quartz.properties文件中注册任意多个插件。然而加载初始化的顺序不能保证,因为Quartz加载所有的属性到Map中然后按map的中的顺序查找插件。
<o:p> </o:p>
To get around this limitation, you can create a Quartz plug-in that acts as a parent plug-in and loads multiple other plug-ins in a given order. Listing 8.6 shows what the ParentPlugin looks like.
<o:p> </o:p>
为绕开这一限制,你可以建立一个Quartz插件做为其他插件的父插件。该插件按指定顺序加载其他插件。列表8.6展示了父插件的样子。
<o:p> </o:p>
Listing 8.6. The ParentPlugin Can Load Child Plug-Ins in a Specified Order<o:p></o:p>
列表8.6 父插件可以按指定顺序加载子插件<o:p></o:p>
- package org.cavaness.quartzbook.chapter8;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.StringTokenizer;
- 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;
- public class ParentPlugin implements SchedulerPlugin {
- private static Log logger = LogFactory.getLog(ParentPlugin.class);
- // A list of child plug-ins
- //子插件列表
- private List childPlugins = new ArrayList();
- private String childPluginNames;
- private String pluginName;
- private Scheduler scheduler;
- /**
- * Default no-arg Constructor
- *
- */
- public ParentPlugin() {
- }
- /**
- * Pass the initialize call on to the child plug-ins.
- *
- * @throws SchedulerConfigException
- * if there is an error initializing.
- */
- public void initialize(String name, final Scheduler scheduler)
- throws SchedulerException {
- this.pluginName = name;
- this.scheduler = scheduler;
- logger.info("Searching for child plugins to load");
- // The child plug-ins are comma-separated
- StringTokenizer tokenizer =
- new StringTokenizer(childPluginNames, ",");
- while (tokenizer.hasMoreElements()) {
- String pluginClassname = tokenizer.nextToken();
- try {
- Class pluginClass =
- Class.forName(pluginClassname);
- Object obj = pluginClass.newInstance();
- // Make sure the specified class is a plug-in
- if (obj instanceof SchedulerPlugin) {
- // Initialize the Plugin
- SchedulerPlugin childPlugin =
- (SchedulerPlugin) obj;
- logger.info("Init child Plugin " +
- pluginClassname);
- childPlugin.initialize(pluginClassname,
- scheduler);
- // Store the child plug-in in the list
- childPlugins.add(childPlugin);
- } else {
- // Skip loading class
- logger.error("Class is not a plugin " +
- pluginClass);
- }
- } catch (Exception ex) {
- // On error, log and go to next child plug-in
- logger.error("Error loading plugin " +
- pluginClassname, ex);
- }
- }
- }
- public void start() {
- // Start each child plug-in
- int size = childPlugins.size();
- for (int i = 0; i < size; i++) {
- SchedulerPlugin childPlugin =
- ((SchedulerPlugin) childPlugins.get(i));
- logger.info("Starting Child Plugin " + childPlugin);
- childPlugin.start();
- }
- }
- public void shutdown() {
- // Stop each child plug-in
- int size = childPlugins.size();
- for (int i = 0; i < size; i++) {
- SchedulerPlugin childPlugin =
- ((SchedulerPlugin) childPlugins.get(i));
- logger.info("Stopping Plugin " + childPlugin);
- childPlugin.shutdown();
- }
- }
- public String getPluginName() {
- return pluginName;
- }
- public void setPluginName(String pluginName) {
- this.pluginName = pluginName;
- }
- public String getChildPluginNames() {
- return childPluginNames;
- }
- public void setChildPluginNames(String childPluginNames) {
- this.childPluginNames = childPluginNames;
- }
- }
- &nbs