From 1737949fc3763fe6463629006677fbecdc80f6fa Mon Sep 17 00:00:00 2001 From: zhouping Date: Fri, 15 May 2020 11:08:50 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-28620=2010.0=E6=89=AB=E6=8F=8F=E5=90=8Eq?= =?UTF-8?q?uartz=E6=9C=89=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fine-quartz-old/pom.xml | 23 +- .../xml/XMLSchedulingDataProcessorPlugin.java | 426 ------ .../org/quartz/xml/ValidationException.java | 144 -- .../xml/XMLSchedulingDataProcessor.java | 1234 ----------------- .../quartz/xml/job_scheduling_data_1_8.xsd | 339 ----- .../quartz/xml/job_scheduling_data_2_0.xsd | 342 ----- fine-third-default/fine-sjsxp/pom.xml | 8 +- 7 files changed, 29 insertions(+), 2487 deletions(-) delete mode 100644 fine-quartz/src/main/java/com/fr/third/v2/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java delete mode 100644 fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/ValidationException.java delete mode 100644 fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/XMLSchedulingDataProcessor.java delete mode 100644 fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_1_8.xsd delete mode 100644 fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_2_0.xsd diff --git a/fine-quartz-old/pom.xml b/fine-quartz-old/pom.xml index 01fca6b85..f42075c1d 100644 --- a/fine-quartz-old/pom.xml +++ b/fine-quartz-old/pom.xml @@ -14,5 +14,26 @@ fine-quartz-old ${revision} - + + + com.fr.third + fine-commons-logging + ${revision} + + + com.fr.third + fine-javax-transaction + ${revision} + + + com.fr.third + fine-mail + ${revision} + + + com.fr.third + fine-druid + ${revision} + + \ No newline at end of file diff --git a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java b/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java deleted file mode 100644 index 9016c35b9..000000000 --- a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright 2001-2010 Terracotta, Inc. - * - * Licensed 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.fr.third.v2.org.quartz.plugins.xml; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -import javax.transaction.UserTransaction; - -import com.fr.third.v2.org.quartz.JobDetail; -import com.fr.third.v2.org.quartz.Scheduler; -import com.fr.third.v2.org.quartz.SchedulerConfigException; -import com.fr.third.v2.org.quartz.SchedulerException; -import com.fr.third.v2.org.quartz.SimpleTrigger; -import com.fr.third.v2.org.quartz.plugins.SchedulerPluginWithUserTransactionSupport; -import com.fr.third.v2.org.quartz.JobBuilder; -import com.fr.third.v2.org.quartz.SimpleScheduleBuilder; -import com.fr.third.v2.org.quartz.TriggerBuilder; -import com.fr.third.v2.org.quartz.TriggerKey; -import com.fr.third.v2.org.quartz.jobs.FileScanJob; -import com.fr.third.v2.org.quartz.jobs.FileScanListener; -import com.fr.third.v2.org.quartz.xml.XMLSchedulingDataProcessor; -import com.fr.third.v2.org.quartz.spi.ClassLoadHelper; - -import static com.fr.third.v2.org.quartz.JobBuilder.newJob; - -/** - * This plugin loads XML file(s) to add jobs and schedule them with triggers - * as the scheduler is initialized, and can optionally periodically scan the - * file for changes. - * - *

The XML schema definition can be found here: - * http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd

- * - *

- * The periodically scanning of files for changes is not currently supported in a - * clustered environment. - *

- * - *

- * If using this plugin with JobStoreCMT, be sure to set the - * plugin property wrapInUserTransaction to true. Also, if you have a - * positive scanInterval be sure to set - * org.quartz.scheduler.wrapJobExecutionInUserTransaction to true. - *

- * - * @see XMLSchedulingDataProcessor - * - * @author James House - * @author Pierre Awaragi - * @author pl47ypus - */ -public class XMLSchedulingDataProcessorPlugin - extends SchedulerPluginWithUserTransactionSupport - implements FileScanListener { - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - private static final int MAX_JOB_TRIGGER_NAME_LEN = 80; - private static final String JOB_INITIALIZATION_PLUGIN_NAME = "JobSchedulingDataLoaderPlugin"; - private static final String FILE_NAME_DELIMITERS = ","; - - private boolean failOnFileNotFound = true; - - private String fileNames = XMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME; - - // Populated by initialization - private Map jobFiles = new LinkedHashMap(); - - private long scanInterval = 0; - - boolean started = false; - - protected ClassLoadHelper classLoadHelper = null; - - private Set jobTriggerNameSet = new HashSet(); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - public XMLSchedulingDataProcessorPlugin() { - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - * Comma separated list of file names (with paths) to the XML files that should be read. - */ - public String getFileNames() { - return fileNames; - } - - /** - * The file name (and path) to the XML file that should be read. - */ - public void setFileNames(String fileNames) { - this.fileNames = fileNames; - } - - /** - * The interval (in seconds) at which to scan for changes to the file. - * If the file has been changed, it is re-loaded and parsed. The default - * value for the interval is 0, which disables scanning. - * - * @return Returns the scanInterval. - */ - public long getScanInterval() { - return scanInterval / 1000; - } - - /** - * The interval (in seconds) at which to scan for changes to the file. - * If the file has been changed, it is re-loaded and parsed. The default - * value for the interval is 0, which disables scanning. - * - * @param scanInterval The scanInterval to set. - */ - public void setScanInterval(long scanInterval) { - this.scanInterval = scanInterval * 1000; - } - - /** - * Whether or not initialization of the plugin should fail (throw an - * exception) if the file cannot be found. Default is true. - */ - public boolean isFailOnFileNotFound() { - return failOnFileNotFound; - } - - /** - * Whether or not initialization of the plugin should fail (throw an - * exception) if the file cannot be found. Default is true. - */ - public void setFailOnFileNotFound(boolean failOnFileNotFound) { - this.failOnFileNotFound = failOnFileNotFound; - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * SchedulerPlugin Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - *

- * Called during creation of the Scheduler in order to give - * the SchedulerPlugin a chance to initialize. - *

- * - * @throws SchedulerConfigException - * if there is an error initializing. - */ - public void initialize(String name, final Scheduler scheduler, ClassLoadHelper schedulerFactoryClassLoadHelper) - throws SchedulerException { - super.initialize(name, scheduler); - this.classLoadHelper = schedulerFactoryClassLoadHelper; - - getLog().info("Registering Quartz Job Initialization Plug-in."); - - // Create JobFile objects - StringTokenizer stok = new StringTokenizer(fileNames, FILE_NAME_DELIMITERS); - while (stok.hasMoreTokens()) { - final String fileName = stok.nextToken(); - final JobFile jobFile = new JobFile(fileName); - jobFiles.put(fileName, jobFile); - } - } - - - @Override - public void start(UserTransaction userTransaction) { - try { - if (jobFiles.isEmpty() == false) { - - if (scanInterval > 0) { - getScheduler().getContext().put(JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName(), this); - } - - Iterator iterator = jobFiles.values().iterator(); - while (iterator.hasNext()) { - JobFile jobFile = iterator.next(); - - if (scanInterval > 0) { - String jobTriggerName = buildJobTriggerName(jobFile.getFileBasename()); - TriggerKey tKey = new TriggerKey(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME); - - // remove pre-existing job/trigger, if any - getScheduler().unscheduleJob(tKey); - - JobDetail job = JobBuilder.newJob().withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME).ofType(FileScanJob.class) - .usingJobData(FileScanJob.FILE_NAME, jobFile.getFileName()) - .usingJobData(FileScanJob.FILE_SCAN_LISTENER_NAME, JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName()) - .build(); - - SimpleTrigger trig = TriggerBuilder.newTrigger().withIdentity(tKey).withSchedule( - SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInMilliseconds(scanInterval)) - .forJob(job) - .build(); - - getScheduler().scheduleJob(job, trig); - getLog().debug("Scheduled file scan job for data file: {}, at interval: {}", jobFile.getFileName(), scanInterval); - } - - processFile(jobFile); - } - } - } catch(SchedulerException se) { - getLog().error("Error starting background-task for watching jobs file.", se); - } finally { - started = true; - } - } - - /** - * Helper method for generating unique job/trigger name for the - * file scanning jobs (one per FileJob). The unique names are saved - * in jobTriggerNameSet. - */ - private String buildJobTriggerName( - String fileBasename) { - // Name w/o collisions will be prefix + _ + filename (with '.' of filename replaced with '_') - // For example: JobInitializationPlugin_jobInitializer_myjobs_xml - String jobTriggerName = JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName() + '_' + fileBasename.replace('.', '_'); - - // If name is too long (DB column is 80 chars), then truncate to max length - if (jobTriggerName.length() > MAX_JOB_TRIGGER_NAME_LEN) { - jobTriggerName = jobTriggerName.substring(0, MAX_JOB_TRIGGER_NAME_LEN); - } - - // Make sure this name is unique in case the same file name under different - // directories is being checked, or had a naming collision due to length truncation. - // If there is a conflict, keep incrementing a _# suffix on the name (being sure - // not to get too long), until we find a unique name. - int currentIndex = 1; - while (jobTriggerNameSet.add(jobTriggerName) == false) { - // If not our first time through, then strip off old numeric suffix - if (currentIndex > 1) { - jobTriggerName = jobTriggerName.substring(0, jobTriggerName.lastIndexOf('_')); - } - - String numericSuffix = "_" + currentIndex++; - - // If the numeric suffix would make the name too long, then make room for it. - if (jobTriggerName.length() > (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())) { - jobTriggerName = jobTriggerName.substring(0, (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())); - } - - jobTriggerName += numericSuffix; - } - - return jobTriggerName; - } - - /** - * Overriden to ignore wrapInUserTransaction because shutdown() - * does not interact with the Scheduler. - */ - @Override - public void shutdown() { - // Since we have nothing to do, override base shutdown so don't - // get extranious UserTransactions. - } - - private void processFile(JobFile jobFile) { - if (jobFile == null || !jobFile.getFileFound()) { - return; - } - - - try { - XMLSchedulingDataProcessor processor = - new XMLSchedulingDataProcessor(this.classLoadHelper); - - processor.addJobGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME); - processor.addTriggerGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME); - - processor.processFileAndScheduleJobs( - jobFile.getFileName(), - jobFile.getFileName(), // systemId - getScheduler()); - } catch (Exception e) { - getLog().error("Error scheduling jobs: " + e.getMessage(), e); - } - } - - public void processFile(String filePath) { - processFile((JobFile)jobFiles.get(filePath)); - } - - /** - * @see FileScanListener#fileUpdated(java.lang.String) - */ - public void fileUpdated(String fileName) { - if (started) { - processFile(fileName); - } - } - - class JobFile { - private String fileName; - - // These are set by initialize() - private String filePath; - private String fileBasename; - private boolean fileFound; - - protected JobFile(String fileName) throws SchedulerException { - this.fileName = fileName; - initialize(); - } - - protected String getFileName() { - return fileName; - } - - protected boolean getFileFound() { - return fileFound; - } - - protected String getFilePath() { - return filePath; - } - - protected String getFileBasename() { - return fileBasename; - } - - private void initialize() throws SchedulerException { - InputStream f = null; - try { - String furl = null; - - File file = new File(getFileName()); // files in filesystem - if (!file.exists()) { - URL url = classLoadHelper.getResource(getFileName()); - if(url != null) { - try { - furl = URLDecoder.decode(url.getPath(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - furl = url.getPath(); - } - file = new File(furl); - try { - f = url.openStream(); - } catch (IOException ignor) { - // Swallow the exception - } - } - } else { - try { - f = new java.io.FileInputStream(file); - }catch (FileNotFoundException e) { - // ignore - } - } - - if (f == null) { - if (isFailOnFileNotFound()) { - throw new SchedulerException( - "File named '" + getFileName() + "' does not exist."); - } else { - getLog().warn("File named '" + getFileName() + "' does not exist."); - } - } else { - fileFound = true; - } - filePath = (furl != null) ? furl : file.getAbsolutePath(); - fileBasename = file.getName(); - } finally { - try { - if (f != null) { - f.close(); - } - } catch (IOException ioe) { - getLog().warn("Error closing jobs file " + getFileName(), ioe); - } - } - } - } -} - -// EOF diff --git a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/ValidationException.java b/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/ValidationException.java deleted file mode 100644 index 3bb4b63ba..000000000 --- a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/ValidationException.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2001-2009 Terracotta, Inc. - * - * Licensed 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.fr.third.v2.org.quartz.xml; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -/** - * Reports JobSchedulingDataLoader validation exceptions. - * - * @author Chris Bonham - */ -public class ValidationException extends Exception { - - private static final long serialVersionUID = -1697832087051681357L; - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - private Collection validationExceptions = new ArrayList(); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - * Constructor for ValidationException. - */ - public ValidationException() { - super(); - } - - /** - * Constructor for ValidationException. - * - * @param message - * exception message. - */ - public ValidationException(String message) { - super(message); - } - - /** - * Constructor for ValidationException. - * - * @param errors - * collection of validation exceptions. - */ - public ValidationException(Collection errors) { - this(); - this.validationExceptions = Collections - .unmodifiableCollection(validationExceptions); - initCause(errors.iterator().next()); - } - - - /** - * Constructor for ValidationException. - * - * @param message - * exception message. - * @param errors - * collection of validation exceptions. - */ - public ValidationException(String message, Collection errors) { - this(message); - this.validationExceptions = Collections - .unmodifiableCollection(validationExceptions); - initCause(errors.iterator().next()); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - * Returns collection of errors. - * - * @return collection of errors. - */ - public Collection getValidationExceptions() { - return validationExceptions; - } - - /** - * Returns the detail message string. - * - * @return the detail message string. - */ - @Override - public String getMessage() { - if (getValidationExceptions().size() == 0) { return super.getMessage(); } - - StringBuffer sb = new StringBuffer(); - - boolean first = true; - - for (Iterator iter = getValidationExceptions().iterator(); iter - .hasNext(); ) { - Exception e = iter.next(); - - if (!first) { - sb.append('\n'); - first = false; - } - - sb.append(e.getMessage()); - } - - return sb.toString(); - } - - -} diff --git a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/XMLSchedulingDataProcessor.java b/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/XMLSchedulingDataProcessor.java deleted file mode 100644 index 8bd0e53fa..000000000 --- a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/XMLSchedulingDataProcessor.java +++ /dev/null @@ -1,1234 +0,0 @@ -/* - * Copyright 2001-2010 Terracotta, Inc. - * - * Licensed 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.fr.third.v2.org.quartz.xml; - -import static com.fr.third.v2.org.quartz.CronScheduleBuilder.cronSchedule; -import static com.fr.third.v2.org.quartz.JobBuilder.newJob; -import static com.fr.third.v2.org.quartz.TriggerKey.triggerKey; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; - -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathException; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import com.fr.third.v2.org.quartz.DateBuilder; -import com.fr.third.v2.org.quartz.Job; -import com.fr.third.v2.org.quartz.JobDetail; -import com.fr.third.v2.org.quartz.JobKey; -import com.fr.third.v2.org.quartz.JobPersistenceException; -import com.fr.third.v2.org.quartz.ScheduleBuilder; -import com.fr.third.v2.org.quartz.Scheduler; -import com.fr.third.v2.org.quartz.SchedulerException; -import com.fr.third.v2.org.quartz.Trigger; -import com.fr.third.v2.org.quartz.impl.matchers.GroupMatcher; -import com.fr.third.v2.org.quartz.CalendarIntervalScheduleBuilder; -import com.fr.third.v2.org.quartz.CronScheduleBuilder; -import com.fr.third.v2.org.quartz.JobBuilder; -import com.fr.third.v2.org.quartz.ObjectAlreadyExistsException; -import com.fr.third.v2.org.quartz.SimpleScheduleBuilder; -import com.fr.third.v2.org.quartz.TriggerBuilder; -import com.fr.third.v2.org.quartz.TriggerKey; -import com.fr.third.v2.org.quartz.spi.MutableTrigger; -import com.fr.third.v2.org.quartz.spi.ClassLoadHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import javax.xml.bind.DatatypeConverter; - - -/** - * Parses an XML file that declares Jobs and their schedules (Triggers), and processes the related data. - * - * The xml document must conform to the format defined in - * "job_scheduling_data_2_0.xsd" - * - * The same instance can be used again and again, however a single instance is not thread-safe. - * - * @author James House - * @author Past contributions from Chris Bonham - * @author Past contributions from pl47ypus - * - * @since Quartz 1.8 - */ -public class XMLSchedulingDataProcessor implements ErrorHandler { - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constants. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - public static final String QUARTZ_NS = "http://www.quartz-scheduler.org/xml/JobSchedulingData"; - - public static final String QUARTZ_SCHEMA_WEB_URL = "http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd"; - - public static final String QUARTZ_XSD_PATH_IN_JAR = "com/fr/third/v2/org/quartz/xml/job_scheduling_data_2_0.xsd"; - - public static final String QUARTZ_XML_DEFAULT_FILE_NAME = "quartz_data.xml"; - - public static final String QUARTZ_SYSTEM_ID_JAR_PREFIX = "jar:"; - - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Data members. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - // pre-processing commands - protected List jobGroupsToDelete = new LinkedList(); - protected List triggerGroupsToDelete = new LinkedList(); - protected List jobsToDelete = new LinkedList(); - protected List triggersToDelete = new LinkedList(); - - // scheduling commands - protected List loadedJobs = new LinkedList(); - protected List loadedTriggers = new LinkedList(); - - // directives - private boolean overWriteExistingData = true; - private boolean ignoreDuplicates = false; - - protected Collection validationExceptions = new ArrayList(); - - - protected ClassLoadHelper classLoadHelper; - protected List jobGroupsToNeverDelete = new LinkedList(); - protected List triggerGroupsToNeverDelete = new LinkedList(); - - private DocumentBuilder docBuilder = null; - private XPath xpath = null; - - private final Logger log = LoggerFactory.getLogger(getClass()); - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Constructors. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - /** - * Constructor for JobSchedulingDataLoader. - * - * @param clh class-loader helper to share with digester. - * @throws ParserConfigurationException if the XML parser cannot be configured as needed. - */ - public XMLSchedulingDataProcessor(ClassLoadHelper clh) throws ParserConfigurationException { - this.classLoadHelper = clh; - initDocumentParser(); - } - - /** - * Initializes the XML parser. - * @throws ParserConfigurationException - */ - protected void initDocumentParser() throws ParserConfigurationException { - - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - - docBuilderFactory.setNamespaceAware(true); - docBuilderFactory.setValidating(true); - - docBuilderFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); - - docBuilderFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", resolveSchemaSource()); - - docBuilder = docBuilderFactory.newDocumentBuilder(); - - docBuilder.setErrorHandler(this); - - NamespaceContext nsContext = new NamespaceContext() - { - public String getNamespaceURI(String prefix) - { - if (prefix == null) - throw new IllegalArgumentException("Null prefix"); - if (XMLConstants.XML_NS_PREFIX.equals(prefix)) - return XMLConstants.XML_NS_URI; - if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) - return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; - - if ("q".equals(prefix)) - return QUARTZ_NS; - - return XMLConstants.NULL_NS_URI; - } - - public Iterator getPrefixes(String namespaceURI) - { - // This method isn't necessary for XPath processing. - throw new UnsupportedOperationException(); - } - - public String getPrefix(String namespaceURI) - { - // This method isn't necessary for XPath processing. - throw new UnsupportedOperationException(); - } - - }; - - xpath = XPathFactory.newInstance().newXPath(); - xpath.setNamespaceContext(nsContext); - } - - protected Object resolveSchemaSource() { - InputSource inputSource; - - InputStream is = null; - - try { - is = classLoadHelper.getResourceAsStream(QUARTZ_XSD_PATH_IN_JAR); - } finally { - if (is != null) { - inputSource = new InputSource(is); - inputSource.setSystemId(QUARTZ_SCHEMA_WEB_URL); - log.debug("Utilizing schema packaged in local quartz distribution jar."); - } - else { - log.info("Unable to load local schema packaged in quartz distribution jar. Utilizing schema online at " + QUARTZ_SCHEMA_WEB_URL); - return QUARTZ_SCHEMA_WEB_URL; - } - - } - - return inputSource; - } - - /** - * Whether the existing scheduling data (with same identifiers) will be - * overwritten. - * - * If false, and IgnoreDuplicates is not false, and jobs or - * triggers with the same names already exist as those in the file, an - * error will occur. - * - * @see #isIgnoreDuplicates() - */ - public boolean isOverWriteExistingData() { - return overWriteExistingData; - } - - /** - * Whether the existing scheduling data (with same identifiers) will be - * overwritten. - * - * If false, and IgnoreDuplicates is not false, and jobs or - * triggers with the same names already exist as those in the file, an - * error will occur. - * - * @see #setIgnoreDuplicates(boolean) - */ - protected void setOverWriteExistingData(boolean overWriteExistingData) { - this.overWriteExistingData = overWriteExistingData; - } - - /** - * If true (and OverWriteExistingData is false) then any - * job/triggers encountered in this file that have names that already exist - * in the scheduler will be ignored, and no error will be produced. - * - * @see #isOverWriteExistingData() - */ - public boolean isIgnoreDuplicates() { - return ignoreDuplicates; - } - - /** - * If true (and OverWriteExistingData is false) then any - * job/triggers encountered in this file that have names that already exist - * in the scheduler will be ignored, and no error will be produced. - * - * @see #setOverWriteExistingData(boolean) - */ - public void setIgnoreDuplicates(boolean ignoreDuplicates) { - this.ignoreDuplicates = ignoreDuplicates; - } - - /** - * Add the given group to the list of job groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public void addJobGroupToNeverDelete(String group) { - if(group != null) - jobGroupsToNeverDelete.add(group); - } - - /** - * Remove the given group to the list of job groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public boolean removeJobGroupToNeverDelete(String group) { - return group != null && jobGroupsToNeverDelete.remove(group); - } - - /** - * Get the (unmodifiable) list of job groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public List getJobGroupsToNeverDelete() { - return Collections.unmodifiableList(jobGroupsToDelete); - } - - /** - * Add the given group to the list of trigger groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public void addTriggerGroupToNeverDelete(String group) { - if(group != null) - triggerGroupsToNeverDelete.add(group); - } - - /** - * Remove the given group to the list of trigger groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public boolean removeTriggerGroupToNeverDelete(String group) { - if(group != null) - return triggerGroupsToNeverDelete.remove(group); - return false; - } - - /** - * Get the (unmodifiable) list of trigger groups that will never be - * deleted by this processor, even if a pre-processing-command to - * delete the group is encountered. - */ - public List getTriggerGroupsToNeverDelete() { - return Collections.unmodifiableList(triggerGroupsToDelete); - } - - /* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Interface. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - - /** - * Process the xml file in the default location (a file named - * "quartz_jobs.xml" in the current working directory). - * - */ - protected void processFile() throws Exception { - processFile(QUARTZ_XML_DEFAULT_FILE_NAME); - } - - /** - * Process the xml file named fileName. - * - * @param fileName - * meta data file name. - */ - protected void processFile(String fileName) throws Exception { - processFile(fileName, getSystemIdForFileName(fileName)); - } - - /** - * For the given fileName, attempt to expand it to its full path - * for use as a system id. - * - * @see #getURL(String) - * @see #processFile() - * @see #processFile(String) - * @see #processFileAndScheduleJobs(Scheduler, boolean) - * @see #processFileAndScheduleJobs(String, Scheduler) - */ - protected String getSystemIdForFileName(String fileName) { - File file = new File(fileName); // files in filesystem - if (file.exists()) { - try { - new FileInputStream(file).close(); - return file.toURI().toString(); - }catch (IOException ignore) { - return fileName; - } - } else { - URL url = getURL(fileName); - if (url == null) { - return fileName; - } else { - try { - url.openStream().close(); - return url.toString(); - } catch (IOException ignore) { - return fileName; - } - } - } - } - - /** - * Returns an URL from the fileName as a resource. - * - * @param fileName - * file name. - * @return an URL from the fileName as a resource. - */ - protected URL getURL(String fileName) { - return classLoadHelper.getResource(fileName); - } - - protected void prepForProcessing() - { - clearValidationExceptions(); - - setOverWriteExistingData(true); - setIgnoreDuplicates(false); - - jobGroupsToDelete.clear(); - jobsToDelete.clear(); - triggerGroupsToDelete.clear(); - triggersToDelete.clear(); - - loadedJobs.clear(); - loadedTriggers.clear(); - } - - /** - * Process the xmlfile named fileName with the given system - * ID. - * - * @param fileName - * meta data file name. - * @param systemId - * system ID. - */ - protected void processFile(String fileName, String systemId) - throws ValidationException, ParserConfigurationException, - SAXException, IOException, SchedulerException, - ClassNotFoundException, ParseException, XPathException { - - prepForProcessing(); - - log.info("Parsing XML file: " + fileName + - " with systemId: " + systemId); - InputSource is = new InputSource(getInputStream(fileName)); - is.setSystemId(systemId); - - process(is); - - maybeThrowValidationException(); - } - - /** - * Process the xmlfile named fileName with the given system - * ID. - * - * @param stream - * an input stream containing the xml content. - * @param systemId - * system ID. - */ - public void processStreamAndScheduleJobs(InputStream stream, String systemId, Scheduler sched) - throws ValidationException, ParserConfigurationException, - SAXException, XPathException, IOException, SchedulerException, - ClassNotFoundException, ParseException { - - prepForProcessing(); - - log.info("Parsing XML from stream with systemId: " + systemId); - - InputSource is = new InputSource(stream); - is.setSystemId(systemId); - - process(is); - executePreProcessCommands(sched); - scheduleJobs(sched); - - maybeThrowValidationException(); - } - - @SuppressWarnings("ConstantConditions") - protected void process(InputSource is) throws SAXException, IOException, ParseException, XPathException, ClassNotFoundException { - - // load the document - Document document = docBuilder.parse(is); - - // - // Extract pre-processing commands - // - - NodeList deleteJobGroupNodes = (NodeList) xpath.evaluate( - "/q:job-scheduling-data/q:pre-processing-commands/q:delete-jobs-in-group", - document, XPathConstants.NODESET); - - log.debug("Found " + deleteJobGroupNodes.getLength() + " delete job group commands."); - - for (int i = 0; i < deleteJobGroupNodes.getLength(); i++) { - Node node = deleteJobGroupNodes.item(i); - String t = node.getTextContent(); - if(t == null || (t = t.trim()).length() == 0) - continue; - jobGroupsToDelete.add(t); - } - - NodeList deleteTriggerGroupNodes = (NodeList) xpath.evaluate( - "/q:job-scheduling-data/q:pre-processing-commands/q:delete-triggers-in-group", - document, XPathConstants.NODESET); - - log.debug("Found " + deleteTriggerGroupNodes.getLength() + " delete trigger group commands."); - - for (int i = 0; i < deleteTriggerGroupNodes.getLength(); i++) { - Node node = deleteTriggerGroupNodes.item(i); - String t = node.getTextContent(); - if(t == null || (t = t.trim()).length() == 0) - continue; - triggerGroupsToDelete.add(t); - } - - NodeList deleteJobNodes = (NodeList) xpath.evaluate( - "/q:job-scheduling-data/q:pre-processing-commands/q:delete-job", - document, XPathConstants.NODESET); - - log.debug("Found " + deleteJobNodes.getLength() + " delete job commands."); - - for (int i = 0; i < deleteJobNodes.getLength(); i++) { - Node node = deleteJobNodes.item(i); - - String name = getTrimmedToNullString(xpath, "q:name", node); - String group = getTrimmedToNullString(xpath, "q:group", node); - - if(name == null) - throw new ParseException("Encountered a 'delete-job' command without a name specified.", -1); - jobsToDelete.add(new JobKey(name, group)); - } - - NodeList deleteTriggerNodes = (NodeList) xpath.evaluate( - "/q:job-scheduling-data/q:pre-processing-commands/q:delete-trigger", - document, XPathConstants.NODESET); - - log.debug("Found " + deleteTriggerNodes.getLength() + " delete trigger commands."); - - for (int i = 0; i < deleteTriggerNodes.getLength(); i++) { - Node node = deleteTriggerNodes.item(i); - - String name = getTrimmedToNullString(xpath, "q:name", node); - String group = getTrimmedToNullString(xpath, "q:group", node); - - if(name == null) - throw new ParseException("Encountered a 'delete-trigger' command without a name specified.", -1); - triggersToDelete.add(new TriggerKey(name, group)); - } - - // - // Extract directives - // - - Boolean overWrite = getBoolean(xpath, - "/q:job-scheduling-data/q:processing-directives/q:overwrite-existing-data", document); - if(overWrite == null) { - log.debug("Directive 'overwrite-existing-data' not specified, defaulting to " + isOverWriteExistingData()); - } - else { - log.debug("Directive 'overwrite-existing-data' specified as: " + overWrite); - setOverWriteExistingData(overWrite); - } - - Boolean ignoreDupes = getBoolean(xpath, - "/q:job-scheduling-data/q:processing-directives/q:ignore-duplicates", document); - if(ignoreDupes == null) { - log.debug("Directive 'ignore-duplicates' not specified, defaulting to " + isIgnoreDuplicates()); - } - else { - log.debug("Directive 'ignore-duplicates' specified as: " + ignoreDupes); - setIgnoreDuplicates(ignoreDupes); - } - - // - // Extract Job definitions... - // - - NodeList jobNodes = (NodeList) xpath.evaluate("/q:job-scheduling-data/q:schedule/q:job", - document, XPathConstants.NODESET); - - log.debug("Found " + jobNodes.getLength() + " job definitions."); - - for (int i = 0; i < jobNodes.getLength(); i++) { - Node jobDetailNode = jobNodes.item(i); - String t = null; - - String jobName = getTrimmedToNullString(xpath, "q:name", jobDetailNode); - String jobGroup = getTrimmedToNullString(xpath, "q:group", jobDetailNode); - String jobDescription = getTrimmedToNullString(xpath, "q:description", jobDetailNode); - String jobClassName = getTrimmedToNullString(xpath, "q:job-class", jobDetailNode); - t = getTrimmedToNullString(xpath, "q:durability", jobDetailNode); - boolean jobDurability = (t != null) && t.equals("true"); - t = getTrimmedToNullString(xpath, "q:recover", jobDetailNode); - boolean jobRecoveryRequested = (t != null) && t.equals("true"); - - Class jobClass = classLoadHelper.loadClass(jobClassName, Job.class); - - JobDetail jobDetail = JobBuilder.newJob(jobClass) - .withIdentity(jobName, jobGroup) - .withDescription(jobDescription) - .storeDurably(jobDurability) - .requestRecovery(jobRecoveryRequested) - .build(); - - NodeList jobDataEntries = (NodeList) xpath.evaluate( - "q:job-data-map/q:entry", jobDetailNode, - XPathConstants.NODESET); - - for (int k = 0; k < jobDataEntries.getLength(); k++) { - Node entryNode = jobDataEntries.item(k); - String key = getTrimmedToNullString(xpath, "q:key", entryNode); - String value = getTrimmedToNullString(xpath, "q:value", entryNode); - jobDetail.getJobDataMap().put(key, value); - } - - if(log.isDebugEnabled()) - log.debug("Parsed job definition: " + jobDetail); - - addJobToSchedule(jobDetail); - } - - // - // Extract Trigger definitions... - // - - NodeList triggerEntries = (NodeList) xpath.evaluate( - "/q:job-scheduling-data/q:schedule/q:trigger/*", document, XPathConstants.NODESET); - - log.debug("Found " + triggerEntries.getLength() + " trigger definitions."); - - for (int j = 0; j < triggerEntries.getLength(); j++) { - Node triggerNode = triggerEntries.item(j); - String triggerName = getTrimmedToNullString(xpath, "q:name", triggerNode); - String triggerGroup = getTrimmedToNullString(xpath, "q:group", triggerNode); - String triggerDescription = getTrimmedToNullString(xpath, "q:description", triggerNode); - String triggerMisfireInstructionConst = getTrimmedToNullString(xpath, "q:misfire-instruction", triggerNode); - String triggerPriorityString = getTrimmedToNullString(xpath, "q:priority", triggerNode); - String triggerCalendarRef = getTrimmedToNullString(xpath, "q:calendar-name", triggerNode); - String triggerJobName = getTrimmedToNullString(xpath, "q:job-name", triggerNode); - String triggerJobGroup = getTrimmedToNullString(xpath, "q:job-group", triggerNode); - - int triggerPriority = Trigger.DEFAULT_PRIORITY; - if(triggerPriorityString != null) - triggerPriority = Integer.valueOf(triggerPriorityString); - - String startTimeString = getTrimmedToNullString(xpath, "q:start-time", triggerNode); - String startTimeFutureSecsString = getTrimmedToNullString(xpath, "q:start-time-seconds-in-future", triggerNode); - String endTimeString = getTrimmedToNullString(xpath, "q:end-time", triggerNode); - - //QTZ-273 : use of DatatypeConverter.parseDateTime() instead of SimpleDateFormat - Date triggerStartTime; - if(startTimeFutureSecsString != null) - triggerStartTime = new Date(System.currentTimeMillis() + (Long.valueOf(startTimeFutureSecsString) * 1000L)); - else - triggerStartTime = (startTimeString == null || startTimeString.length() == 0 ? new Date() : DatatypeConverter.parseDateTime(startTimeString).getTime()); - Date triggerEndTime = endTimeString == null || endTimeString.length() == 0 ? null : DatatypeConverter.parseDateTime(endTimeString).getTime(); - - TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup); - - ScheduleBuilder sched; - - if (triggerNode.getNodeName().equals("simple")) { - String repeatCountString = getTrimmedToNullString(xpath, "q:repeat-count", triggerNode); - String repeatIntervalString = getTrimmedToNullString(xpath, "q:repeat-interval", triggerNode); - - int repeatCount = repeatCountString == null ? 0 : Integer.parseInt(repeatCountString); - long repeatInterval = repeatIntervalString == null ? 0 : Long.parseLong(repeatIntervalString); - - sched = SimpleScheduleBuilder.simpleSchedule() - .withIntervalInMilliseconds(repeatInterval) - .withRepeatCount(repeatCount); - - if (triggerMisfireInstructionConst != null && triggerMisfireInstructionConst.length() != 0) { - if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_FIRE_NOW")) - ((SimpleScheduleBuilder)sched).withMisfireHandlingInstructionFireNow(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT")) - ((SimpleScheduleBuilder)sched).withMisfireHandlingInstructionNextWithExistingCount(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT")) - ((SimpleScheduleBuilder)sched).withMisfireHandlingInstructionNextWithRemainingCount(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT")) - ((SimpleScheduleBuilder)sched).withMisfireHandlingInstructionNowWithExistingCount(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT")) - ((SimpleScheduleBuilder)sched).withMisfireHandlingInstructionNowWithRemainingCount(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_SMART_POLICY")) { - // do nothing.... (smart policy is default) - } - else - throw new ParseException("Unexpected/Unhandlable Misfire Instruction encountered '" + triggerMisfireInstructionConst + "', for trigger: " + triggerKey, -1); - } - } else if (triggerNode.getNodeName().equals("cron")) { - String cronExpression = getTrimmedToNullString(xpath, "q:cron-expression", triggerNode); - String timezoneString = getTrimmedToNullString(xpath, "q:time-zone", triggerNode); - - TimeZone tz = timezoneString == null ? null : TimeZone.getTimeZone(timezoneString); - - sched = CronScheduleBuilder.cronSchedule(cronExpression) - .inTimeZone(tz); - - if (triggerMisfireInstructionConst != null && triggerMisfireInstructionConst.length() != 0) { - if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_DO_NOTHING")) - ((CronScheduleBuilder)sched).withMisfireHandlingInstructionDoNothing(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_FIRE_ONCE_NOW")) - ((CronScheduleBuilder)sched).withMisfireHandlingInstructionFireAndProceed(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_SMART_POLICY")) { - // do nothing.... (smart policy is default) - } - else - throw new ParseException("Unexpected/Unhandlable Misfire Instruction encountered '" + triggerMisfireInstructionConst + "', for trigger: " + triggerKey, -1); - } - } else if (triggerNode.getNodeName().equals("calendar-interval")) { - String repeatIntervalString = getTrimmedToNullString(xpath, "q:repeat-interval", triggerNode); - String repeatUnitString = getTrimmedToNullString(xpath, "q:repeat-interval-unit", triggerNode); - - int repeatInterval = Integer.parseInt(repeatIntervalString); - - DateBuilder.IntervalUnit repeatUnit = DateBuilder.IntervalUnit.valueOf(repeatUnitString); - - sched = CalendarIntervalScheduleBuilder.calendarIntervalSchedule() - .withInterval(repeatInterval, repeatUnit); - - if (triggerMisfireInstructionConst != null && triggerMisfireInstructionConst.length() != 0) { - if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_DO_NOTHING")) - ((CalendarIntervalScheduleBuilder)sched).withMisfireHandlingInstructionDoNothing(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_FIRE_ONCE_NOW")) - ((CalendarIntervalScheduleBuilder)sched).withMisfireHandlingInstructionFireAndProceed(); - else if(triggerMisfireInstructionConst.equals("MISFIRE_INSTRUCTION_SMART_POLICY")) { - // do nothing.... (smart policy is default) - } - else - throw new ParseException("Unexpected/Unhandlable Misfire Instruction encountered '" + triggerMisfireInstructionConst + "', for trigger: " + triggerKey, -1); - } - } else { - throw new ParseException("Unknown trigger type: " + triggerNode.getNodeName(), -1); - } - - - MutableTrigger trigger = (MutableTrigger) TriggerBuilder.newTrigger() - .withIdentity(triggerName, triggerGroup) - .withDescription(triggerDescription) - .forJob(triggerJobName, triggerJobGroup) - .startAt(triggerStartTime) - .endAt(triggerEndTime) - .withPriority(triggerPriority) - .modifiedByCalendar(triggerCalendarRef) - .withSchedule(sched) - .build(); - - NodeList jobDataEntries = (NodeList) xpath.evaluate( - "q:job-data-map/q:entry", triggerNode, - XPathConstants.NODESET); - - for (int k = 0; k < jobDataEntries.getLength(); k++) { - Node entryNode = jobDataEntries.item(k); - String key = getTrimmedToNullString(xpath, "q:key", entryNode); - String value = getTrimmedToNullString(xpath, "q:value", entryNode); - trigger.getJobDataMap().put(key, value); - } - - if(log.isDebugEnabled()) - log.debug("Parsed trigger definition: " + trigger); - - addTriggerToSchedule(trigger); - } - } - - protected String getTrimmedToNullString(XPath xpathToElement, String elementName, Node parentNode) throws XPathExpressionException { - String str = (String) xpathToElement.evaluate(elementName, - parentNode, XPathConstants.STRING); - - if(str != null) - str = str.trim(); - - if(str != null && str.length() == 0) - str = null; - - return str; - } - - protected Boolean getBoolean(XPath xpathToElement, String elementName, Document document) throws XPathExpressionException { - - Node directive = (Node) xpathToElement.evaluate(elementName, document, XPathConstants.NODE); - - if(directive == null || directive.getTextContent() == null) - return null; - - String val = directive.getTextContent(); - if(val.equalsIgnoreCase("true") || val.equalsIgnoreCase("yes") || val.equalsIgnoreCase("y")) - return Boolean.TRUE; - - return Boolean.FALSE; - } - - /** - * Process the xml file in the default location, and schedule all of the - * jobs defined within it. - * - *

Note that we will set overWriteExistingJobs after the default xml is parsed. - */ - public void processFileAndScheduleJobs(Scheduler sched, - boolean overWriteExistingJobs) throws Exception { - String fileName = QUARTZ_XML_DEFAULT_FILE_NAME; - processFile(fileName, getSystemIdForFileName(fileName)); - // The overWriteExistingJobs flag was set by processFile() -> prepForProcessing(), then by xml parsing, and then now - // we need to reset it again here by this method parameter to override it. - setOverWriteExistingData(overWriteExistingJobs); - executePreProcessCommands(sched); - scheduleJobs(sched); - } - - /** - * Process the xml file in the given location, and schedule all of the - * jobs defined within it. - * - * @param fileName - * meta data file name. - */ - public void processFileAndScheduleJobs(String fileName, Scheduler sched) throws Exception { - processFileAndScheduleJobs(fileName, getSystemIdForFileName(fileName), sched); - } - - /** - * Process the xml file in the given location, and schedule all of the - * jobs defined within it. - * - * @param fileName - * meta data file name. - */ - public void processFileAndScheduleJobs(String fileName, String systemId, Scheduler sched) throws Exception { - processFile(fileName, systemId); - executePreProcessCommands(sched); - scheduleJobs(sched); - } - - /** - * Returns a List of jobs loaded from the xml file. - *

- * - * @return a List of jobs. - */ - protected List getLoadedJobs() { - return Collections.unmodifiableList(loadedJobs); - } - - /** - * Returns a List of triggers loaded from the xml file. - *

- * - * @return a List of triggers. - */ - protected List getLoadedTriggers() { - return Collections.unmodifiableList(loadedTriggers); - } - - /** - * Returns an InputStream from the fileName as a resource. - * - * @param fileName - * file name. - * @return an InputStream from the fileName as a resource. - */ - protected InputStream getInputStream(String fileName) { - return this.classLoadHelper.getResourceAsStream(fileName); - } - - protected void addJobToSchedule(JobDetail job) { - loadedJobs.add(job); - } - - protected void addTriggerToSchedule(MutableTrigger trigger) { - loadedTriggers.add(trigger); - } - - private Map> buildTriggersByFQJobNameMap(List triggers) { - - Map> triggersByFQJobName = new HashMap>(); - - for(MutableTrigger trigger: triggers) { - List triggersOfJob = triggersByFQJobName.get(trigger.getJobKey()); - if(triggersOfJob == null) { - triggersOfJob = new LinkedList(); - triggersByFQJobName.put(trigger.getJobKey(), triggersOfJob); - } - triggersOfJob.add(trigger); - } - - return triggersByFQJobName; - } - - protected void executePreProcessCommands(Scheduler scheduler) - throws SchedulerException { - - for(String group: jobGroupsToDelete) { - if(group.equals("*")) { - log.info("Deleting all jobs in ALL groups."); - for (String groupName : scheduler.getJobGroupNames()) { - if (!jobGroupsToNeverDelete.contains(groupName)) { - for (JobKey key : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) { - scheduler.deleteJob(key); - } - } - } - } - else { - if(!jobGroupsToNeverDelete.contains(group)) { - log.info("Deleting all jobs in group: {}", group); - for (JobKey key : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) { - scheduler.deleteJob(key); - } - } - } - } - - for(String group: triggerGroupsToDelete) { - if(group.equals("*")) { - log.info("Deleting all triggers in ALL groups."); - for (String groupName : scheduler.getTriggerGroupNames()) { - if (!triggerGroupsToNeverDelete.contains(groupName)) { - for (TriggerKey key : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName))) { - scheduler.unscheduleJob(key); - } - } - } - } - else { - if(!triggerGroupsToNeverDelete.contains(group)) { - log.info("Deleting all triggers in group: {}", group); - for (TriggerKey key : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(group))) { - scheduler.unscheduleJob(key); - } - } - } - } - - for(JobKey key: jobsToDelete) { - if(!jobGroupsToNeverDelete.contains(key.getGroup())) { - log.info("Deleting job: {}", key); - scheduler.deleteJob(key); - } - } - - for(TriggerKey key: triggersToDelete) { - if(!triggerGroupsToNeverDelete.contains(key.getGroup())) { - log.info("Deleting trigger: {}", key); - scheduler.unscheduleJob(key); - } - } - } - - /** - * Schedules the given sets of jobs and triggers. - * - * @param sched - * job scheduler. - * @exception SchedulerException - * if the Job or Trigger cannot be added to the Scheduler, or - * there is an internal Scheduler error. - */ - @SuppressWarnings("ConstantConditions") - protected void scheduleJobs(Scheduler sched) - throws SchedulerException { - - List jobs = new LinkedList(getLoadedJobs()); - List triggers = new LinkedList( getLoadedTriggers()); - - log.info("Adding " + jobs.size() + " jobs, " + triggers.size() + " triggers."); - - Map> triggersByFQJobName = buildTriggersByFQJobNameMap(triggers); - - // add each job, and it's associated triggers - Iterator itr = jobs.iterator(); - while(itr.hasNext()) { - JobDetail detail = itr.next(); - itr.remove(); // remove jobs as we handle them... - - JobDetail dupeJ = null; - try { - // The existing job could have been deleted, and Quartz API doesn't allow us to query this without - // loading the job class, so use try/catch to handle it. - dupeJ = sched.getJobDetail(detail.getKey()); - } catch (JobPersistenceException e) { - if (e.getCause() instanceof ClassNotFoundException && isOverWriteExistingData()) { - // We are going to replace jobDetail anyway, so just delete it first. - log.info("Removing job: " + detail.getKey()); - sched.deleteJob(detail.getKey()); - } else { - throw e; - } - } - - if ((dupeJ != null)) { - if(!isOverWriteExistingData() && isIgnoreDuplicates()) { - log.info("Not overwriting existing job: " + dupeJ.getKey()); - continue; // just ignore the entry - } - if(!isOverWriteExistingData() && !isIgnoreDuplicates()) { - throw new ObjectAlreadyExistsException(detail); - } - } - - if (dupeJ != null) { - log.info("Replacing job: " + detail.getKey()); - } else { - log.info("Adding job: " + detail.getKey()); - } - - List triggersOfJob = triggersByFQJobName.get(detail.getKey()); - - if (!detail.isDurable() && (triggersOfJob == null || triggersOfJob.size() == 0)) { - if (dupeJ == null) { - throw new SchedulerException( - "A new job defined without any triggers must be durable: " + - detail.getKey()); - } - - if ((dupeJ.isDurable() && - (sched.getTriggersOfJob( - detail.getKey()).size() == 0))) { - throw new SchedulerException( - "Can't change existing durable job without triggers to non-durable: " + - detail.getKey()); - } - } - - - if(dupeJ != null || detail.isDurable()) { - if (triggersOfJob != null && triggersOfJob.size() > 0) - sched.addJob(detail, true, true); // add the job regardless is durable or not b/c we have trigger to add - else - sched.addJob(detail, true, false); // add the job only if a replacement or durable, else exception will throw! - } - else { - boolean addJobWithFirstSchedule = true; - - // Add triggers related to the job... - for (MutableTrigger trigger : triggersOfJob) { - triggers.remove(trigger); // remove triggers as we handle them... - - if (trigger.getStartTime() == null) { - trigger.setStartTime(new Date()); - } - - Trigger dupeT = sched.getTrigger(trigger.getKey()); - if (dupeT != null) { - if (isOverWriteExistingData()) { - if (log.isDebugEnabled()) { - log.debug( - "Rescheduling job: " + trigger.getJobKey() + " with updated trigger: " + trigger.getKey()); - } - } else if (isIgnoreDuplicates()) { - log.info("Not overwriting existing trigger: " + dupeT.getKey()); - continue; // just ignore the trigger (and possibly job) - } else { - throw new ObjectAlreadyExistsException(trigger); - } - - if (!dupeT.getJobKey().equals(trigger.getJobKey())) { - log.warn("Possibly duplicately named ({}) triggers in jobs xml file! ", trigger.getKey()); - } - - sched.rescheduleJob(trigger.getKey(), trigger); - } else { - if (log.isDebugEnabled()) { - log.debug( - "Scheduling job: " + trigger.getJobKey() + " with trigger: " + trigger.getKey()); - } - - try { - if (addJobWithFirstSchedule) { - sched.scheduleJob(detail, trigger); // add the job if it's not in yet... - addJobWithFirstSchedule = false; - } else { - sched.scheduleJob(trigger); - } - } catch (ObjectAlreadyExistsException e) { - if (log.isDebugEnabled()) { - log.debug( - "Adding trigger: " + trigger.getKey() + " for job: " + detail.getKey() + - " failed because the trigger already existed. " + - "This is likely due to a race condition between multiple instances " + - "in the cluster. Will try to reschedule instead."); - } - - // Let's try one more time as reschedule. - sched.rescheduleJob(trigger.getKey(), trigger); - } - } - } - } - } - - // add triggers that weren't associated with a new job... (those we already handled were removed above) - for(MutableTrigger trigger: triggers) { - - if(trigger.getStartTime() == null) { - trigger.setStartTime(new Date()); - } - - Trigger dupeT = sched.getTrigger(trigger.getKey()); - if (dupeT != null) { - if(isOverWriteExistingData()) { - if (log.isDebugEnabled()) { - log.debug( - "Rescheduling job: " + trigger.getJobKey() + " with updated trigger: " + trigger.getKey()); - } - } - else if(isIgnoreDuplicates()) { - log.info("Not overwriting existing trigger: " + dupeT.getKey()); - continue; // just ignore the trigger - } - else { - throw new ObjectAlreadyExistsException(trigger); - } - - if(!dupeT.getJobKey().equals(trigger.getJobKey())) { - log.warn("Possibly duplicately named ({}) triggers in jobs xml file! ", trigger.getKey()); - } - - sched.rescheduleJob(trigger.getKey(), trigger); - } else { - if (log.isDebugEnabled()) { - log.debug( - "Scheduling job: " + trigger.getJobKey() + " with trigger: " + trigger.getKey()); - } - - try { - sched.scheduleJob(trigger); - } catch (ObjectAlreadyExistsException e) { - if (log.isDebugEnabled()) { - log.debug( - "Adding trigger: " + trigger.getKey() + " for job: " +trigger.getJobKey() + - " failed because the trigger already existed. " + - "This is likely due to a race condition between multiple instances " + - "in the cluster. Will try to reschedule instead."); - } - - // Let's rescheduleJob one more time. - sched.rescheduleJob(trigger.getKey(), trigger); - } - } - } - } - - /** - * ErrorHandler interface. - * - * Receive notification of a warning. - * - * @param e - * The error information encapsulated in a SAX parse exception. - * @exception SAXException - * Any SAX exception, possibly wrapping another exception. - */ - public void warning(SAXParseException e) throws SAXException { - addValidationException(e); - } - - /** - * ErrorHandler interface. - * - * Receive notification of a recoverable error. - * - * @param e - * The error information encapsulated in a SAX parse exception. - * @exception SAXException - * Any SAX exception, possibly wrapping another exception. - */ - public void error(SAXParseException e) throws SAXException { - addValidationException(e); - } - - /** - * ErrorHandler interface. - * - * Receive notification of a non-recoverable error. - * - * @param e - * The error information encapsulated in a SAX parse exception. - * @exception SAXException - * Any SAX exception, possibly wrapping another exception. - */ - public void fatalError(SAXParseException e) throws SAXException { - addValidationException(e); - } - - /** - * Adds a detected validation exception. - * - * @param e - * SAX exception. - */ - protected void addValidationException(SAXException e) { - validationExceptions.add(e); - } - - /** - * Resets the the number of detected validation exceptions. - */ - protected void clearValidationExceptions() { - validationExceptions.clear(); - } - - /** - * Throws a ValidationException if the number of validationExceptions - * detected is greater than zero. - * - * @exception ValidationException - * DTD validation exception. - */ - protected void maybeThrowValidationException() throws ValidationException { - if (validationExceptions.size() > 0) { - throw new ValidationException("Encountered " + validationExceptions.size() + " validation exceptions.", validationExceptions); - } - } -} diff --git a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_1_8.xsd b/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_1_8.xsd deleted file mode 100644 index e8d0d23c9..000000000 --- a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_1_8.xsd +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - Root level node - - - - - - Commands to be executed before scheduling the jobs and triggers in this file. - - - - - Directives to be followed while scheduling the jobs and triggers in this file. - - - - - - - - - - - - - - Version of the XML Schema instance - - - - - - - - - Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. - - - Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. - - - Delete the identified job if it exists (will also result in deleting all triggers related to it). - - - - - - - - - Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). - - - - - - - - - - - - - - Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. - - - If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. - - - - - - - Define a JobDetail - - - - - - - - - - - - - - - - - - - Define a JobDataMap - - - - - - - - - Define a JobDataMap entry - - - - - - - - - - Define a Trigger - - - - - - - - - - - Common Trigger definitions - - - - - - - - - - - - - - - - - - - - Define a SimpleTrigger - - - - - - - - - - - - - - - - - Define a CronTrigger - - - - - - - - - - - - - - - Define a DateIntervalTrigger - - - - - - - - - - - - - - - - Cron expression (see JavaDoc for examples) - - Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! - - Regular expressions are not my strong point but I believe this is complete, - with the caveat that order for expressions like 3-0 is not legal but will pass, - and month and day names must be capitalized. - If you want to examine the correctness look for the [\s] to denote the - seperation of individual regular expressions. This is how I break them up visually - to examine them: - - SECONDS: - ( - ((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9])) - | (([\*]|[0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9])) - | ([\?]) - | ([\*]) - ) [\s] - MINUTES: - ( - ((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9])) - | (([\*]|[0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9])) - | ([\?]) - | ([\*]) - ) [\s] - HOURS: - ( - ((([0-9]|[0-1][0-9]|[2][0-3]),)*([0-9]|[0-1][0-9]|[2][0-3])) - | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])(/|-)([0-9]|[0-1][0-9]|[2][0-3])) - | ([\?]) - | ([\*]) - ) [\s] - DAY OF MONTH: - ( - ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]),)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) - | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(/|-)([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) - | (L) - | (LW) - | ([1-9]W) - | ([1-3][0-9]W) - | ([\?]) - | ([\*]) - )[\s] - MONTH: - ( - ((([1-9]|0[1-9]|1[0-2]),)*([1-9]|0[1-9]|1[0-2])) - | (([1-9]|0[1-9]|1[0-2])(/|-)([1-9]|0[1-9]|1[0-2])) - | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC),)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) - | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-|/)(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) - | ([\?]) - | ([\*]) - )[\s] - DAY OF WEEK: - ( - (([1-7],)*([1-7])) - | ([1-7](/|-)([1-7])) - | (((MON|TUE|WED|THU|FRI|SAT|SUN),)*(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) - | ((MON|TUE|WED|THU|FRI|SAT|SUN)(-|/)(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) - | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) - | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) - | ([\?]) - | ([\*]) - ) - YEAR (OPTIONAL): - ( - [\s]? - ([\*])? - | ((19[7-9][0-9])|(20[0-9][0-9]))? - | (((19[7-9][0-9])|(20[0-9][0-9]))(-|/)((19[7-9][0-9])|(20[0-9][0-9])))? - | ((((19[7-9][0-9])|(20[0-9][0-9])),)*((19[7-9][0-9])|(20[0-9][0-9])))? - ) - - - - - - - - - - Number of times to repeat the Trigger (-1 for indefinite) - - - - - - - - - - Simple Trigger Misfire Instructions - - - - - - - - - - - - - - Simple Trigger Misfire Instructions - - - - - - - - - - - Date Interval Trigger Misfire Instructions - - - - - - - - - - - Interval Units - - - - - - - - - - - - - diff --git a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_2_0.xsd b/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_2_0.xsd deleted file mode 100644 index bad0b0e86..000000000 --- a/fine-quartz/src/main/java/com/fr/third/v2/org/quartz/xml/job_scheduling_data_2_0.xsd +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - Root level node - - - - - - Commands to be executed before scheduling the jobs and triggers in this file. - - - - - Directives to be followed while scheduling the jobs and triggers in this file. - - - - - - - - - - - - - - Version of the XML Schema instance - - - - - - - - - Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. - - - Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. - - - Delete the identified job if it exists (will also result in deleting all triggers related to it). - - - - - - - - - Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). - - - - - - - - - - - - - - Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. - - - If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. - - - - - - - Define a JobDetail - - - - - - - - - - - - - - - - - Define a JobDataMap - - - - - - - - - Define a JobDataMap entry - - - - - - - - - - Define a Trigger - - - - - - - - - - - Common Trigger definitions - - - - - - - - - - - - - - - - - - - - - - - Define a SimpleTrigger - - - - - - - - - - - - - - - - - Define a CronTrigger - - - - - - - - - - - - - - - Define a DateIntervalTrigger - - - - - - - - - - - - - - - - Cron expression (see JavaDoc for examples) - - Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! - - Regular expressions are not my strong point but I believe this is complete, - with the caveat that order for expressions like 3-0 is not legal but will pass, - and month and day names must be capitalized. - If you want to examine the correctness look for the [\s] to denote the - seperation of individual regular expressions. This is how I break them up visually - to examine them: - - SECONDS: - ( - ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) - | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) - | ([\?]) - | ([\*]) - ) [\s] - MINUTES: - ( - ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) - | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) - | ([\?]) - | ([\*]) - ) [\s] - HOURS: - ( - ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) - | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) - | ([\?]) - | ([\*]) - ) [\s] - DAY OF MONTH: - ( - ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) - | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) - | (L(-[0-9])?) - | (L(-[1-2][0-9])?) - | (L(-[3][0-1])?) - | (LW) - | ([1-9]W) - | ([1-3][0-9]W) - | ([\?]) - | ([\*]) - )[\s] - MONTH: - ( - ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) - | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) - | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) - | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) - | ([\?]) - | ([\*]) - )[\s] - DAY OF WEEK: - ( - (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) - | ([1-7]/([1-7])) - | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) - | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) - | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) - | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) - | ([\?]) - | ([\*]) - ) - YEAR (OPTIONAL): - ( - [\s]? - ([\*])? - | ((19[7-9][0-9])|(20[0-9][0-9]))? - | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? - | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? - ) - - - - - - - - - - Number of times to repeat the Trigger (-1 for indefinite) - - - - - - - - - - Simple Trigger Misfire Instructions - - - - - - - - - - - - - - Cron Trigger Misfire Instructions - - - - - - - - - - - Date Interval Trigger Misfire Instructions - - - - - - - - - - - Interval Units - - - - - - - - - - - - - diff --git a/fine-third-default/fine-sjsxp/pom.xml b/fine-third-default/fine-sjsxp/pom.xml index b32b177b8..6dc30c69a 100644 --- a/fine-third-default/fine-sjsxp/pom.xml +++ b/fine-third-default/fine-sjsxp/pom.xml @@ -13,5 +13,11 @@ fine-sjsxp ${revision} - + + + com.fr.third + fine-stax + ${revision} + + \ No newline at end of file