[
  {
    "path": ".gitattributes",
    "content": "#\n# https://help.github.com/articles/dealing-with-line-endings/\n#\n# Linux start script should use lf\n/gradlew        text eol=lf\n\n# These are Windows script files and should use crlf\n*.bat           text eol=crlf\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file\n\nversion: 2\nupdates:\n  - package-ecosystem: \"gradle\" # See documentation for possible values\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    target-branch: main\n    ignore:\n      - dependency-name: \"org.mockito:mockito-core\"\n\n  - package-ecosystem: \"gradle\" # See documentation for possible values\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    target-branch: quartz-2.4.x\n    ignore:\n      - dependency-name: \"org.mockito:mockito-core\"\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "\n<!--\nIf this is your first time contributing to the project (or it's been a while), please consider reviewing https://github.com/quartz-scheduler/contributing/blob/main/CONTRIBUTING.md\n-->\n\n\nThis PR...\n\nFixes issue #\n\n## Changes\n-\n\n-----------------\n## Checklist\n- [ ] tested locally\n- [ ] updated the docs\n- [ ] added appropriate test\n- [ ] signed-off on the DCO referenced in the CONTRIBUTING link below via `git commit -s` on my commits, and submit this code under terms of the Apache 2.0 license and assign copyright to the Quartz project owners\n  (If you're not using command-line, you can use a [browser extension](https://github.com/scottrigby/dco-gh-ui) )\n-----------------\nIn submitting this contribution, I agree to the terms of contributing as referred to here: \nhttps://github.com/quartz-scheduler/contributing/blob/main/CONTRIBUTING.md\n\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Configuration for probot-stale - https://github.com/probot/stale\n\n# Number of days of inactivity before an Issue or Pull Request becomes stale\ndaysUntilStale: 90\n\n# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.\n# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.\ndaysUntilClose: 10\n\n# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)\nonlyLabels: []\n\n# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable\nexemptLabels:\n  - todo\n\n# Set to true to ignore issues in a project (defaults to false)\nexemptProjects: false\n\n# Set to true to ignore issues in a milestone (defaults to false)\nexemptMilestones: true\n\n# Set to true to ignore issues with an assignee (defaults to false)\nexemptAssignees: false\n\n# Label to use when marking as stale\nstaleLabel: stale\n\n# Comment to post when marking as stale. Set to `false` to disable\nmarkComment: >\n  Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?\n  This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.\n\n# Comment to post when removing the stale label.\n# unmarkComment: >\n#   Your comment here.\n\n# Comment to post when closing a stale Issue or Pull Request.\n# closeComment: >\n#   Your comment here.\n\n# Limit the number of actions per hour, from 1-30. Default is 30\nlimitPerRun: 30\n\n# Limit to only `issues` or `pulls`\n# only: issues\n\n# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':\n# pulls:\n#   daysUntilStale: 30\n#   markComment: >\n#     This pull request has been automatically marked as stale because it has not had\n#     recent activity. It will be closed if no further activity occurs. Thank you\n#     for your contributions.\n\n# issues:\n#   exemptLabels:\n#     - confirmed\n"
  },
  {
    "path": ".gitignore",
    "content": "# gradle\n.gradle/\n**/build/\n!**/src/**/build\n\n# misplaced test artifacts\nderby.log\nlogs/\ntmp/\n\n# IntelliJ IDEA noise\nout/\n.idea/\n*.iml\n*.ipr\n*.iws\n\n# Eclipse IDE noise\n.settings/\n.project\n.classpath\n\n# NetBeans noise\nnbproject/\n\n# Other Editor's noise\n*~\n*.swp\n\n# MacOSX noise\n.DS_Store\n\n# Ignore Gradle project-specific cache directory\n.gradle\n\n# Ignore Gradle build output directory\nbuild\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n# Contributing to the Quartz Scheduler Project\n\n_We're happy to have you participate in our community with your contributions!_\n\nThanks for your interest in contributing to the to the Quartz Scheduler Project.\n\nStart your journey by reading here: [Contributing](https://github.com/quartz-scheduler/contributing/blob/main/CONTRIBUTING.md)\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "azure-pipelines.yml",
    "content": "#\n# Copyright Terracotta, Inc.\n# Copyright IBM Corp. 2024, 2025\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# See shared code location for steps and parameters:\n# https://dev.azure.com/TerracottaCI/_git/terracotta\n\nresources:\n  repositories:\n    - repository: templates\n      type: git\n      name: terracotta/terracotta\n\njobs:\n  - template: build-templates/gradle-common.yml@templates\n    parameters:\n      jobName: Java11\n      jdkVersion: '1.11'\n      options: '-Dtest.databasePort=1527'\n  - template: build-templates/gradle-common.yml@templates\n    parameters:\n      jobName: Java17\n      jdkVersion: '1.17'\n      options: '-Dtest.databasePort=1527'\n  - template: build-templates/gradle-common.yml@templates\n    parameters:\n      jobName: Java21\n      jdkVersion: '1.21'\n      options: '-Dtest.databasePort=1527'\n\n"
  },
  {
    "path": "build.gradle",
    "content": "import org.gradle.api.publish.maven.internal.publication.MavenPomInternal;\nimport org.gradle.api.publish.maven.internal.publisher.MavenPublicationCoordinates;\nimport static org.gradle.api.publish.plugins.PublishingPlugin.PUBLISH_TASK_GROUP;\n\nplugins {\n    // This adds tasks to auto close or release nexus staging repos\n    // see https://github.com/gradle-nexus/publish-plugin/\n    id \"io.github.gradle-nexus.publish-plugin\"\n}\n\n\nallprojects {\n    group 'org.quartz-scheduler'\n    version quartzVersion\n}\n\nsubprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n\nallprojects {\n    plugins.withType(JavaBasePlugin) {\n        java {\n            toolchain {\n                languageVersion = JavaLanguageVersion.of(11)\n            }\n        }\n    }\n\n    plugins.withType(MavenPublishPlugin) {\n        plugins.apply(SigningPlugin)\n        signing {\n            required { !version.endsWith(\"SNAPSHOT\") }\n            sign publishing.publications\n        }\n\n        publishing {\n            configurations {\n                provided\n                runtimeClasspath.extendsFrom(provided)\n            }\n            publications {\n                maven(MavenPublication) {\n                    pom {\n                        name = \"$project.name\"\n                        url = 'https://www.quartz-scheduler.org/'\n                        licenses {\n                            license {\n                                name = 'The Apache License, Version 2.0'\n                                url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                            }\n                        }\n                        scm {\n                            connection = 'scm:git:git://github.com:quartz-scheduler/quartz.git'\n                            developerConnection = 'scm:git:ssh:git@github.com:quartz-scheduler/quartz.git'\n                            url = 'https://github.com/quartz-scheduler/quartz'\n                        }\n                        developers {\n                            developer {\n                                name = \"Terracotta Engineers\"\n                                email = \"tc-oss@wwpdl.vnet.ibm.com\"\n                                organization = \"IBM Corp.\"\n                                organizationUrl = \"http://www.quartz-scheduler.org/\"\n                            }\n                        }\n                    }\n\n                    from components.java\n                    pom.withXml {\n                        asNode()\n                                .dependencies\n                                .dependency\n                                .findAll { dependency ->\n                                    // Patch up dependency scopes per expectations of maven users\n                                    (dependency.groupId.text() == 'com.mchange' ||\n                                            dependency.groupId.text() == 'com.zaxxer' ||\n                                            dependency.artifactId.text() == 'slf4j-log4j12' ||\n                                            dependency.groupId.text() == 'jakarta.xml' )\n                                }\n                                .each { dependency ->\n                                    // Set scope value to compile.\n                                    dependency.scope*.value = 'provided'\n                                }\n                    }\n                }\n            }\n        }\n\n        // for MANIFEST.MF\n        jar {\n            manifest {\n                attributes(\n                        \"Implementation-Title\": project.name,\n                        \"Implementation-Vendor-Id\": project.group,\n                        \"Implementation-Version\": project.version,\n                        \"Built-By\": System.getProperty(\"user.name\"),\n                        \"Built-JDK\": System.getProperty(\"java.version\"),\n                        \"Automatic-Module-Name\": 'org.quartz',\n                        \"-removeheaders\": 'Private-Package',\n                        \"Export-Package\": 'org.quartz.*',\n                        \"Import-Package\": '*;resolution:=optional'\n                )\n            }\n        }\n\n    }\n\n    // Put pom.xml and pom.properties in the jar:\n    project.afterEvaluate{p ->\n        // module.json publishing confuses sonatype and it doesn't process the jar.\n        tasks.withType(GenerateModuleMetadata) {\n            enabled = false\n        }\n        tasks.withType(GenerateMavenPom) {pomTask ->\n            MavenPublicationCoordinates coordinates = ((MavenPomInternal) pomTask.getPom()).getCoordinates()\n            TaskProvider<WriteProperties> pomPropertiesTask = project.getTasks().register(pomTask.getName().replace(\"PomFile\", \"PomProperties\"), WriteProperties.class, task -> {\n                task.dependsOn(pomTask);\n                task.setGroup(PUBLISH_TASK_GROUP);\n                task.setOutputFile(new File(pomTask.getDestination().getParentFile(), \"pom.properties\"));\n                task.property(\"groupId\", coordinates.getGroupId());\n                task.property(\"artifactId\", coordinates.getArtifactId());\n                task.property(\"version\", coordinates.getVersion());\n            });\n\n            project.tasks.withType(Jar).configureEach{jar ->\n                jar.into(\"META-INF/maven/\" + coordinates.getGroupId().get() + \"/\" + coordinates.getArtifactId().get(), spec -> {\n                    spec.from(pomTask, pom -> pom.rename(\".*\", \"pom.xml\"));\n                    spec.from(pomPropertiesTask);\n                });\n            }\n        }\n    }\n\n}\n\nnexusPublishing {\n    repositories {\n        sonatype{\n            nexusUrl.set(uri(\"https://ossrh-staging-api.central.sonatype.com/service/local/\"))\n            snapshotRepositoryUrl.set(uri(\"https://central.sonatype.com/repository/maven-snapshots/\"))\n        }\n    }\n}\n"
  },
  {
    "path": "checkstyle/README.txt",
    "content": "\nCheckstyle configuration files can be found under src/main/resources\n\n1. You can edit checkstyle rules in checkstyle.xml\n\n2. You can suppress a rule for any files in suppressions.xml\n\n3. You can suppress a rule in a source file with comment:\n\n// CHECKSTYLE_OFF: NameOfTheCheck|OtherTheCheck\n{ code }\n// CHECKSTYLE_ON: NameOfTheCheck|OtherTheCheck\n\n"
  },
  {
    "path": "checkstyle/src/main/resources/checkstyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!DOCTYPE module PUBLIC\n    \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n    \"http://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n\n<module name=\"Checker\">\n  <property name=\"severity\" value=\"error\" />\n\n  <!--module name=\"Header\">\n    <property name=\"headerFile\" value=\"${checkstyle.header.file}\" />\n    <message key=\"header.missing\" value=\"Source file missing Quartz license header\" />\n    <message key=\"header.mismatch\" value=\"Quartz license header mismatch\" />\n  </module-->\n\n  <module name=\"FileTabCharacter\" />\n\n  <module name=\"TreeWalker\">\n    <module name=\"FileContentsHolder\"/>   \n  </module>\n  \n  <module name=\"SuppressionCommentFilter\">\n      <property name=\"offCommentFormat\" value=\"CHECKSTYLE_OFF\\: ([\\w\\|]+)\"/>\n      <property name=\"onCommentFormat\" value=\"CHECKSTYLE_ON\\: ([\\w\\|]+)\"/>\n      <property name=\"checkFormat\" value=\"$1\"/>\n  </module>\n</module>\n\n"
  },
  {
    "path": "checkstyle/src/main/resources/header.txt",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n"
  },
  {
    "path": "checkstyle/src/main/resources/suppressions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!DOCTYPE suppressions PUBLIC\n    \"-//Puppy Crawl//DTD Suppressions 1.1//EN\"\n    \"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd\">\n\n<suppressions>\n  \n</suppressions>\n"
  },
  {
    "path": "docs/index.md",
    "content": "\n# Quartz Documentation\n\nQuartz Documentation for various releases can be found on the Quartz website:\n\n[Quartz Documentation](https://www.quartz-scheduler.org/documentation/)\n\n<br/>\n<br/>\n\nThe source files for the documentation on the site can be found here:\n[Doc Source](https://github.com/quartz-scheduler/quartz-scheduler.org-site/tree/master/documentation)\n\n"
  },
  {
    "path": "examples/build.gradle",
    "content": "plugins {\n    id 'java'\n}\n\ndependencies {\n    implementation project(':quartz')\n    implementation project(':quartz-jobs')\n\n    implementation \"org.slf4j:slf4j-api:$slf4jVersion\"\n    implementation \"org.slf4j:slf4j-log4j12:$slf4jVersion\"\n}\n\ntasks.withType(JavaExec).configureEach {\n    classpath = sourceSets.main.runtimeClasspath\n    group = JavaBasePlugin.DOCUMENTATION_GROUP\n}\n\ntasks.register('runExample1', JavaExec) {\n    description = 'Run Example 1'\n    mainClass = 'org.quartz.examples.example1.SimpleExample'\n}\ntasks.register('runExample2', JavaExec) {\n    description = 'Run Example 2'\n    mainClass = 'org.quartz.examples.example2.SimpleTriggerExample'\n}\ntasks.register('runExample3', JavaExec) {\n    description = 'Run Example 3'\n    mainClass = 'org.quartz.examples.example3.CronTriggerExample'\n}\ntasks.register('runExample4', JavaExec) {\n    description = 'Run Example 4'\n    mainClass = 'org.quartz.examples.example4.JobStateExample'\n}\ntasks.register('runExample5', JavaExec) {\n    description = 'Run Example 5'\n    mainClass = 'org.quartz.examples.example5.MisfireExample'\n}\ntasks.register('runExample6', JavaExec) {\n    description = 'Run Example 6'\n    mainClass = 'org.quartz.examples.example6.JobExceptionExample'\n}\ntasks.register('runExample7', JavaExec) {\n    description = 'Run Example 7'\n    mainClass = 'org.quartz.examples.example7.InterruptExample'\n}\ntasks.register('runExample8', JavaExec) {\n    description = 'Run Example 8'\n    mainClass = 'org.quartz.examples.example8.CalendarExample'\n}\ntasks.register('runExample9', JavaExec) {\n    description = 'Run Example 9'\n    mainClass = 'org.quartz.examples.example9.ListenerExample'\n}\ntasks.register('runEExample10', JavaExec) {\n    description = 'Run Example 10'\n    mainClass = 'org.quartz.examples.example10.PlugInExample'\n    systemProperty('org.quartz.properties', 'org/quartz/examples/example10/quartz.properties')\n}\ntasks.register('runExample11', JavaExec) {\n    description = 'Run Example 11'\n    mainClass = 'org.quartz.examples.example11.LoadExample'\n    systemProperty 'org.quartz.properties', 'org/quartz/examples/example11/quartz.properties'\n}\ntasks.register('runExample12Client', JavaExec) {\n    description = 'Run Example 12 Client'\n    mainClass = 'org.quartz.examples.example12.RemoteClientExample'\n    systemProperty 'org.quartz.properties', 'org/quartz/examples/example12/client.properties'\n}\ntasks.register('runExample12Server', JavaExec) {\n    description = 'Run Example 12 Server'\n    mainClass = 'org.quartz.examples.example12.RemoteServerExample'\n    systemProperty 'org.quartz.properties', 'org/quartz/examples/example12/server.properties'\n}\ntasks.register('runExample13Instance1', JavaExec) {\n    description = 'Run Example 13 Instance 1'\n    mainClass = 'org.quartz.examples.example13.ClusterExample'\n    systemProperty 'org.quartz.properties', 'org/quartz/examples/example13/instance1.properties'\n}\ntasks.register('runExample13Instance2', JavaExec) {\n    description = 'Run Example 13 Instance 2'\n    mainClass = 'org.quartz.examples.example13.ClusterExample'\n    systemProperty 'org.quartz.properties', 'org/quartz/examples/example13/instance2.properties'\n}\ntasks.register('runExample14', JavaExec) {\n    description = 'Run Example 14'\n    mainClass = 'org.quartz.examples.example14.PriorityExample'\n}\ntasks.register('runExample15', JavaExec) {\n    description = 'Run Example 15'\n    mainClass = \"org.quartz.examples.example15.NativeJobExample\"\n}\n"
  },
  {
    "path": "examples/examples_guide.txt",
    "content": "Welcome\n=======\n\nWelcome to the Quartz Examples directory.  \n\nThis directory contains 15 examples that show you how to use various\nfeatures of Quartz.   Each example is located in its own subdirectory. \nEvery example can be run using Windows .bat files or Linux/UNIX .sh files.  \n\nAdditionally, each example directory contains a readme.txt file.  Please \nread this file first, as it will contain useful information for running \nthe examples.\n\n\nExamples Listing\n================\n\nexample1 -  Your first Quartz Program\nexample2 -  Using Simple Triggers\nexample3 -  Using Cron Triggers\nexample4 -  Job State and Job Parameters\nexample5 -  Job Misfires\nexample6 -  Handling Job Exceptions\nexample7 -  Interrupting Jobs\nexample8 -  How to use Quartz Calendars\nexample9 -  Using Job Listeners\nexample10 - Using Quartz Plug-Ins\nexample11 - Loading Up Quartz with Many Jobs\nexample12 - Remoting with Quartz using RMI\nexample13 - Clustering Quartz and JDBC Job Stores\nexample14 - Quartz Trigger Priorities\nexample15 - Running a native (shell) command from a Job\n\n\nFurther description of each example and possible configuration changes to them\nis documented on the example class javadoc themselves, e.g. within\nexamples/src/main/java/org/quartz/examples/example11/LoadExample.java\n\nRunning the Examples\n====================\n\nThe examples can be run from the examples folder of the repository, such as this:\n\n../gradlew :examples:runExample1\n\nor\n\n../gradlew :examples:runExample4\n\nor etc.\n\n\nNote that examples 12 and 13 require running two process (this will need to be\ndone in separate terminals, or on separate machines):\n\nFor Example 12 you need to first run the \"server\" portion, and then run the\n\"client\" portion of the example:\n\n../gradlew :examples:runExample12Server\n../gradlew :examples:runExample12Client\n\nFor Example 13 you need to run two instances (two cluster members):\n\n../gradlew :examples:runExample13Instance1\n../gradlew :examples:runExample13Instance2\n\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example1/HelloJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example1;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * This is just a simple job that says \"Hello\" to the world.\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class HelloJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);\n\n    /**\n     * <p>\n     * Empty constructor for job initialization\n     * </p>\n     * <p>\n     * Quartz requires a public empty constructor so that the\n     * scheduler can instantiate the class whenever it needs.\n     * </p>\n     */\n    public HelloJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // Say Hello to the World and display the date/time\n        _log.info(\"Hello World! - \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example1/SimpleExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example1;\n\nimport static org.quartz.DateBuilder.evenMinuteDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.Trigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This Example will demonstrate how to start and shutdown the Quartz scheduler and how to schedule a job to run in\n * Quartz.\n * \n * @author Bill Kratzer\n */\npublic class SimpleExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(SimpleExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    // computer a time that is on the next round minute\n    Date runTime = evenMinuteDate(new Date());\n\n    log.info(\"------- Scheduling Job  -------------------\");\n\n    // define the job and tie it to our HelloJob class\n    JobDetail job = newJob(HelloJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    // Trigger the job to run on the next round minute\n    Trigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(runTime).build();\n\n    // Tell quartz to schedule the job using our trigger\n    sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + runTime);\n\n    // Start up the scheduler (nothing can actually run until the\n    // scheduler has been started)\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    // wait long enough so that the scheduler as an opportunity to\n    // run the job!\n    log.info(\"------- Waiting 65 seconds... -------------\");\n    try {\n      // wait 65 seconds to show job\n      Thread.sleep(65L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    SimpleExample example = new SimpleExample();\n    example.run();\n\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example10/PlugInExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example10;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This example will spawn a large number of jobs to run\n * \n * @author James House, Bill Kratzer\n */\npublic class PlugInExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(PlugInExample.class);\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = null;\n    try {\n      sched = sf.getScheduler();\n    } catch (NoClassDefFoundError e) {\n      log.error(\" Unable to load a class - most likely you do not have jta.jar on the classpath. If not present in the examples/lib folder, please \" +\n                \"add it there for this sample to run.\", e);\n      return;\n    }\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- (Not directly Scheduling any Jobs - relying on XML definitions of jobs/triggers to be loaded by plugin --\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // start the schedule\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Waiting five minutes... -----------\");\n\n    // wait five minutes to give our jobs a chance to run\n    try {\n      Thread.sleep(300L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    PlugInExample example = new PlugInExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example10/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example10;\n\nimport java.util.Date;\nimport java.util.Set;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);\n\n    /**\n     * Empty constructor for job initialization\n     */\n    public SimpleJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"Executing job: \" + jobKey + \" executing at \" + new Date() + \", fired by: \" + context.getTrigger().getKey());\n        \n        if(context.getMergedJobDataMap().size() > 0) {\n            Set<String> keys = context.getMergedJobDataMap().keySet();\n            for(String key: keys) {\n                String val = context.getMergedJobDataMap().getString(key);\n                _log.info(\" - jobDataMap entry: \" + key + \" = \" + val);\n            }\n        }\n        \n        context.setResult(\"hello\");\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example11/LoadExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example11;\n\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This example will spawn a large number of jobs to run\n *\n * This example demonstrates how Quartz can handle a large\n * number of jobs.   This example starts with 500 jobs.  However,\n * this number can be changed by modifying the start scripts.\n *\n * Due to the size of the thread pool (this example uses as thread\n * count of 15), only 15 threads will run concurrently in the\n * scheduler.\n *\n * You can change this parameter in the quartz.properties file.\n * \n * @author James House, Bill Kratzer\n */\npublic class LoadExample {\n\n  private int _numberOfJobs = 500;\n\n  public LoadExample(int inNumberOfJobs) {\n    _numberOfJobs = inNumberOfJobs;\n  }\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(LoadExample.class);\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    // schedule 500 jobs to run\n    for (int count = 1; count <= _numberOfJobs; count++) {\n      JobDetail job = newJob(SimpleJob.class).withIdentity(\"job\" + count, \"group_1\").requestRecovery() // ask scheduler\n                                                                                                       // to re-execute\n                                                                                                       // this job if it\n                                                                                                       // was in\n                                                                                                       // progress when\n                                                                                                       // the scheduler\n                                                                                                       // went down...\n          .build();\n\n      // tell the job to delay some small amount... to simulate work...\n      long timeDelay = (long) (java.lang.Math.random() * 2500);\n      job.getJobDataMap().put(SimpleJob.DELAY_TIME, timeDelay);\n\n      Trigger trigger = newTrigger().withIdentity(\"trigger_\" + count, \"group_1\")\n          .startAt(futureDate((10000 + (count * 100)), IntervalUnit.MILLISECOND)) // space fire times a small bit\n          .build();\n\n      sched.scheduleJob(job, trigger);\n      if (count % 25 == 0) {\n        log.info(\"...scheduled \" + count + \" jobs\");\n      }\n    }\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // start the schedule\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Waiting five minutes... -----------\");\n\n    // wait five minutes to give our jobs a chance to run\n    try {\n      Thread.sleep(300L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    int numberOfJobs = 500;\n    if (args.length == 1) {\n      numberOfJobs = Integer.parseInt(args[0]);\n    }\n    if (args.length > 1) {\n      System.out.println(\"Usage: java \" + LoadExample.class.getName() + \"[# of jobs]\");\n      return;\n    }\n    LoadExample example = new LoadExample(numberOfJobs);\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example11/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example11;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob implements Job {\n\n  private static Logger      _log       = LoggerFactory.getLogger(SimpleJob.class);\n\n  // job parameter\n  public static final String DELAY_TIME = \"delay time\";\n\n  /**\n   * Empty constructor for job initialization\n   */\n  public SimpleJob() {\n  }\n\n  /**\n   * <p>\n   * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code> fires that\n   * is associated with the <code>Job</code>.\n   * </p>\n   * \n   * @throws JobExecutionException if there is an exception while executing the job.\n   */\n  public void execute(JobExecutionContext context) throws JobExecutionException {\n\n    // This job simply prints out its job name and the\n    // date and time that it is running\n    JobKey jobKey = context.getJobDetail().getKey();\n    _log.info(\"Executing job: \" + jobKey + \" executing at \" + new Date());\n\n    // wait for a period of time\n    long delayTime = context.getJobDetail().getJobDataMap().getLong(DELAY_TIME);\n    try {\n      Thread.sleep(delayTime);\n    } catch (Exception e) {\n      //\n    }\n\n    _log.info(\"Finished Executing job: \" + jobKey + \" at \" + new Date());\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example12/RemoteClientExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example12;\n\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.Trigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This example is a client program that will remotely \n * talk to the scheduler to schedule a job.   In this \n * example, we will need to use the JDBC Job Store.  The \n * client will connect to the JDBC Job Store remotely to \n * schedule the job.\n *\n * This example demonstrates how Quartz can be used in a client/server\n * environment to remotely schedule jobs on a remote server using\n * RMI (Remote Method Invocation).\n *\n * This example will run a server that will execute the schedule.  The\n * server itself will not schedule any jobs.   This example will also\n * execute a client that will connect to the server (via RMI) to\n * schedule the job.  Once the job is remotely scheduled, the scheduler on\n * the server will run the job (at the correct time).\n *\n * Note:  This example works best when you run the client and server on\n * different computers.  However, you can certainly run the server and\n * the client on the same box!\n *\n * Port # used for RMI connection can be modified in the example's\n * property files\n *\n * @author James House, Bill Kratzer\n */\npublic class RemoteClientExample {\n\n    public void run() throws Exception {\n\n        Logger log = LoggerFactory.getLogger(RemoteClientExample.class);\n\n        // First we must get a reference to a scheduler\n        SchedulerFactory sf = new StdSchedulerFactory();\n        Scheduler sched = sf.getScheduler();\n\n        // define the job and ask it to run\n        JobDetail job = newJob(SimpleJob.class)\n            .withIdentity(\"remotelyAddedJob\", \"default\")\n            .build();\n        \n        JobDataMap map = job.getJobDataMap();\n        map.put(\"msg\", \"Your remotely added job has executed!\");\n        \n        Trigger trigger = newTrigger()\n            .withIdentity(\"remotelyAddedTrigger\", \"default\")\n            .forJob(job.getKey())\n            .withSchedule(cronSchedule(\"/5 * * ? * *\"))\n            .build();\n\n        // schedule the job\n        sched.scheduleJob(job, trigger);\n\n        log.info(\"Remote job scheduled.\");\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        RemoteClientExample example = new RemoteClientExample();\n        example.run();\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example12/RemoteServerExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example12;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n *  This example demonstrates how Quartz can be used in a client/server\n *  environment to remotely schedule jobs on a remote server using\n *  RMI (Remote Method Invocation).\n *\n *  This example will run a server that will execute the schedule.  The\n *  server itself will not schedule any jobs.   This example will also\n *  execute a client that will connect to the server (via RMI) to\n *  schedule the job.  Once the job is remotely scheduled, the scheduler on\n *  the server will run the job (at the correct time).\n *  Note:  This example works best when you run the client and server on\n *  different computers.  However, you can certainly run the server and\n *  the client on the same box!\n *\n *  Port # used for RMI connection can be modified in the example's\n *  property files\n *\n * @author Bill Kratzer\n */\npublic class RemoteServerExample {\n\n  /**\n   * This example will spawn a large number of jobs to run\n   * \n   * @author James House, Bill Kratzer\n   */\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(RemoteServerExample.class);\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- (Not Scheduling any Jobs - relying on a remote client to schedule jobs --\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // start the schedule\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Waiting ten minutes... ------------\");\n\n    // wait five minutes to give our jobs a chance to run\n    try {\n      Thread.sleep(600L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    RemoteServerExample example = new RemoteServerExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example12/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example12;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\n\n/**\n * <p>\n * A dumb implementation of Job, for unittesting purposes.\n * </p>\n * \n * @author James House\n */\npublic class SimpleJob implements Job {\n\n    public static final String MESSAGE = \"msg\";\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);\n\n    /**\n     * Quartz requires a public empty constructor so that the\n     * scheduler can instantiate the class whenever it needs.\n     */\n    public SimpleJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n\n        String message = (String) context.getJobDetail().getJobDataMap().get(MESSAGE);\n\n        _log.info(\"SimpleJob: \" + jobKey + \" executing at \" + new Date());\n        _log.info(\"SimpleJob: msg: \" + message);\n    }\n\n    \n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example13/ClusterExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example13;\n\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Used to test/show the clustering features of JDBCJobStore (JobStoreTX or JobStoreCMT).\n * <p>\n * All instances MUST use a different properties file, because their instance Ids must be different, however all other\n * properties should be the same.\n * </p>\n * <p>\n * If you want it to clear out existing jobs and triggers, pass a command-line argument called \"clearJobs\".\n * </p>\n * <p>\n * You should probably start with a \"fresh\" set of tables (assuming you may have some data lingering in it from other\n * tests), since mixing data from a non-clustered setup with a clustered one can be bad.\n * </p>\n * <p>\n * Try killing one of the cluster instances while they are running, and see that the remaining instance(s) recover the\n * in-progress jobs. Note that detection of the failure may take up to 15 or so seconds with the default settings.\n * </p>\n * <p>\n * Also try running it with/without the shutdown-hook plugin registered with the scheduler.\n * (org.quartz.plugins.management.ShutdownHookPlugin).\n * </p>\n * <p>\n * <i>Note:</i> Never run clustering on separate machines, unless their clocks are synchronized using some form of\n * time-sync service (such as an NTP daemon).\n * </p>\n *\n * Configure the instance1.properties file and the instance2.properties\n * file as necessary (see the \"Configuration\" section below for details).\n *\n * This example uses a database to maintain scheduling information in a\n * clustered environment.   You will need to first install the Quartz\n * database tables.  SQL table creation scripts are included with the Quartz\n * distribution for many popular database platforms.\n *\n * You will need a JDBC Driver for your database. The example uses Postgres to demonstrate\n * You can download Postgres JDBC driver here http://jdbc.postgresql.org\n * Just put the jar under \"lib\" folder of the Quartz distribution\n *\n * After you have installed the database scripts, you will need to\n * configure both properties file so that Quartz knows how to connect to\n * your database.\n *\n * The following parameters need to be set: (this shows a PostgreSQL example)\n *\n * <pre>\n * org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX\n * org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate\n * org.quartz.jobStore.useProperties=false\n * org.quartz.jobStore.dataSource=myDS\n * org.quartz.jobStore.tablePrefix=QRTZ_\n * org.quartz.jobStore.isClustered=true\n *\n * org.quartz.dataSource.myDS.driver = org.postgresql.Driver\n * org.quartz.dataSource.myDS.URL = jdbc:postgresql://localhost:5432/quartz\n * org.quartz.dataSource.myDS.user = quartz\n * org.quartz.dataSource.myDS.password = quartz\n * org.quartz.dataSource.myDS.maxConnections = 5\n * org.quartz.dataSource.myDS.validationQuery=\n * </pre>\n *\n * @see SimpleRecoveryJob\n * @see SimpleRecoveryStatefulJob\n * @author James House\n */\npublic class ClusterExample {\n\n  private static Logger _log = LoggerFactory.getLogger(ClusterExample.class);\n\n  public void run(boolean inClearJobs, boolean inScheduleJobs) throws Exception {\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    if (inClearJobs) {\n      _log.warn(\"***** Deleting existing jobs/triggers *****\");\n      sched.clear();\n    }\n\n    _log.info(\"------- Initialization Complete -----------\");\n\n    if (inScheduleJobs) {\n\n      _log.info(\"------- Scheduling Jobs ------------------\");\n\n      String schedId = sched.getSchedulerInstanceId();\n\n      int count = 1;\n\n      JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity(\"job_\" + count, schedId) // put triggers in group\n                                                                                            // named after the cluster\n                                                                                            // node instance just to\n                                                                                            // distinguish (in logging)\n                                                                                            // what was scheduled from\n                                                                                            // where\n          .requestRecovery() // ask scheduler to re-execute this job if it was in progress when the scheduler went\n                             // down...\n          .build();\n\n      SimpleTrigger trigger = newTrigger().withIdentity(\"trigger_\" + count, schedId)\n          .startAt(futureDate(1, IntervalUnit.SECOND))\n          .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();\n\n      _log.info(job.getKey() + \" will run at: \" + trigger.getNextFireTime() + \" and repeat: \"\n                + trigger.getRepeatCount() + \" times, every \" + trigger.getRepeatInterval() / 1000 + \" seconds\");\n      sched.scheduleJob(job, trigger);\n\n      count++;\n\n      job = newJob(SimpleRecoveryJob.class).withIdentity(\"job_\" + count, schedId) // put triggers in group named after\n                                                                                  // the cluster node instance just to\n                                                                                  // distinguish (in logging) what was\n                                                                                  // scheduled from where\n          .requestRecovery() // ask scheduler to re-execute this job if it was in progress when the scheduler went\n                             // down...\n          .build();\n\n      trigger = newTrigger().withIdentity(\"trigger_\" + count, schedId).startAt(futureDate(2, IntervalUnit.SECOND))\n          .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();\n\n      _log.info(job.getKey() + \" will run at: \" + trigger.getNextFireTime() + \" and repeat: \"\n                + trigger.getRepeatCount() + \" times, every \" + trigger.getRepeatInterval() / 1000 + \" seconds\");\n      sched.scheduleJob(job, trigger);\n\n      count++;\n\n      job = newJob(SimpleRecoveryStatefulJob.class).withIdentity(\"job_\" + count, schedId) // put triggers in group named\n                                                                                          // after the cluster node\n                                                                                          // instance just to\n                                                                                          // distinguish (in logging)\n                                                                                          // what was scheduled from\n                                                                                          // where\n          .requestRecovery() // ask scheduler to re-execute this job if it was in progress when the scheduler went\n                             // down...\n          .build();\n\n      trigger = newTrigger().withIdentity(\"trigger_\" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))\n          .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(3)).build();\n\n      _log.info(job.getKey() + \" will run at: \" + trigger.getNextFireTime() + \" and repeat: \"\n                + trigger.getRepeatCount() + \" times, every \" + trigger.getRepeatInterval() / 1000 + \" seconds\");\n      sched.scheduleJob(job, trigger);\n\n      count++;\n\n      job = newJob(SimpleRecoveryJob.class).withIdentity(\"job_\" + count, schedId) // put triggers in group named after\n                                                                                  // the cluster node instance just to\n                                                                                  // distinguish (in logging) what was\n                                                                                  // scheduled from where\n          .requestRecovery() // ask scheduler to re-execute this job if it was in progress when the scheduler went\n                             // down...\n          .build();\n\n      trigger = newTrigger().withIdentity(\"trigger_\" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))\n          .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(4)).build();\n\n      _log.info(job.getKey() + \" will run at: \" + trigger.getNextFireTime() + \" & repeat: \" + trigger.getRepeatCount()\n                + \"/\" + trigger.getRepeatInterval());\n      sched.scheduleJob(job, trigger);\n\n      count++;\n\n      job = newJob(SimpleRecoveryJob.class).withIdentity(\"job_\" + count, schedId) // put triggers in group named after\n                                                                                  // the cluster node instance just to\n                                                                                  // distinguish (in logging) what was\n                                                                                  // scheduled from where\n          .requestRecovery() // ask scheduler to re-execute this job if it was in progress when the scheduler went\n                             // down...\n          .build();\n\n      trigger = newTrigger().withIdentity(\"trigger_\" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))\n          .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInMilliseconds(4500L)).build();\n\n      _log.info(job.getKey() + \" will run at: \" + trigger.getNextFireTime() + \" & repeat: \" + trigger.getRepeatCount()\n                + \"/\" + trigger.getRepeatInterval());\n      sched.scheduleJob(job, trigger);\n    }\n\n    // jobs don't start firing until start() has been called...\n    _log.info(\"------- Starting Scheduler ---------------\");\n    sched.start();\n    _log.info(\"------- Started Scheduler ----------------\");\n\n    _log.info(\"------- Waiting for one hour... ----------\");\n    try {\n      Thread.sleep(3600L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    _log.info(\"------- Shutting Down --------------------\");\n    sched.shutdown();\n    _log.info(\"------- Shutdown Complete ----------------\");\n  }\n\n  public static void main(String[] args) throws Exception {\n    boolean clearJobs = false;\n    boolean scheduleJobs = true;\n\n    for (String arg : args) {\n      if (arg.equalsIgnoreCase(\"clearJobs\")) {\n        clearJobs = true;\n      } else if (arg.equalsIgnoreCase(\"dontScheduleJobs\")) {\n        scheduleJobs = false;\n      }\n    }\n\n    ClusterExample example = new ClusterExample();\n    example.run(clearJobs, scheduleJobs);\n  }\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example13/SimpleRecoveryJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example13;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * <p>\n * A dumb implementation of Job, for unit testing purposes.\n * </p>\n * \n * @author James House\n */\npublic class SimpleRecoveryJob implements Job {\n\n  private static Logger       _log  = LoggerFactory.getLogger(SimpleRecoveryJob.class);\n\n  private static final String COUNT = \"count\";\n\n  /**\n   * Quartz requires a public empty constructor so that the scheduler can instantiate the class whenever it needs.\n   */\n  public SimpleRecoveryJob() {\n  }\n\n  /**\n   * <p>\n   * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code> fires that\n   * is associated with the <code>Job</code>.\n   * </p>\n   * \n   * @throws JobExecutionException if there is an exception while executing the job.\n   */\n  public void execute(JobExecutionContext context) throws JobExecutionException {\n\n    JobKey jobKey = context.getJobDetail().getKey();\n\n    // if the job is recovering print a message\n    if (context.isRecovering()) {\n      _log.info(\"SimpleRecoveryJob: \" + jobKey + \" RECOVERING at \" + new Date());\n    } else {\n      _log.info(\"SimpleRecoveryJob: \" + jobKey + \" starting at \" + new Date());\n    }\n\n    // delay for ten seconds\n    long delay = 10L * 1000L;\n    try {\n      Thread.sleep(delay);\n    } catch (Exception e) {\n      //\n    }\n\n    JobDataMap data = context.getJobDetail().getJobDataMap();\n    int count;\n    if (data.containsKey(COUNT)) {\n      count = data.getInt(COUNT);\n    } else {\n      count = 0;\n    }\n    count++;\n    data.put(COUNT, count);\n\n    _log.info(\"SimpleRecoveryJob: \" + jobKey + \" done at \" + new Date() + \"\\n Execution #\" + count);\n\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example13/SimpleRecoveryStatefulJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example13;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.PersistJobDataAfterExecution;\n\n/**\n * This job has the same functionality of SimpleRecoveryJob except that this job implements is 'stateful', in that it\n * will have it's data (JobDataMap) automatically re-persisted after each execution, and only one instance of the\n * JobDetail can be executed at a time.\n * \n * @author Bill Kratzer\n */\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic class SimpleRecoveryStatefulJob extends SimpleRecoveryJob {\n\n  public SimpleRecoveryStatefulJob() {\n    super();\n  }\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example14/PriorityExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n package org.quartz.examples.example14;\n\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.Trigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This Example will demonstrate how Triggers are ordered by priority.\n */\npublic class PriorityExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(PriorityExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory(\"org/quartz/examples/example14/quartz_priority.properties\");\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    JobDetail job = newJob(TriggerEchoJob.class).withIdentity(\"TriggerEchoJob\").build();\n\n    // All three triggers will fire their first time at the same time,\n    // ordered by their priority, and then repeat once, firing in a\n    // staggered order that therefore ignores priority.\n    //\n    // We should see the following firing order:\n    // 1. Priority10Trigger15SecondRepeat\n    // 2. Priority5Trigger10SecondRepeat\n    // 3. Priority1Trigger5SecondRepeat\n    // 4. Priority1Trigger5SecondRepeat\n    // 5. Priority5Trigger10SecondRepeat\n    // 6. Priority10Trigger15SecondRepeat\n\n    // Calculate the start time of all triggers as 5 seconds from now\n    Date startTime = futureDate(5, IntervalUnit.SECOND);\n\n    // First trigger has priority of 1, and will repeat after 5 seconds\n    Trigger trigger1 = newTrigger().withIdentity(\"Priority1Trigger5SecondRepeat\").startAt(startTime)\n        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)).withPriority(1).forJob(job).build();\n\n    // Second trigger has default priority of 5 (default), and will repeat after 10 seconds\n    Trigger trigger2 = newTrigger().withIdentity(\"Priority5Trigger10SecondRepeat\").startAt(startTime)\n        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(10)).forJob(job).build();\n\n    // Third trigger has priority 10, and will repeat after 15 seconds\n    Trigger trigger3 = newTrigger().withIdentity(\"Priority10Trigger15SecondRepeat\").startAt(startTime)\n        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(15)).withPriority(10).forJob(job)\n        .build();\n\n    // Tell quartz to schedule the job using our trigger\n    sched.scheduleJob(job, trigger1);\n    sched.scheduleJob(trigger2);\n    sched.scheduleJob(trigger3);\n\n    // Start up the scheduler (nothing can actually run until the\n    // scheduler has been started)\n    sched.start();\n    log.info(\"------- Started Scheduler -----------------\");\n\n    // wait long enough so that the scheduler as an opportunity to\n    // fire the triggers\n    log.info(\"------- Waiting 30 seconds... -------------\");\n    try {\n      Thread.sleep(30L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n  }\n\n  public static void main(String[] args) throws Exception {\n    PriorityExample example = new PriorityExample();\n    example.run();\n  }\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example14/TriggerEchoJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n package org.quartz.examples.example14;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * This is just a simple job that echos the name of the Trigger\n * that fired it.\n */\npublic class TriggerEchoJob implements Job {\n\n    private static final Logger LOG = LoggerFactory.getLogger(TriggerEchoJob.class);\n\n    /**\n     * Empty constructor for job initialization\n     *\n     * <p>\n     * Quartz requires a public empty constructor so that the\n     * scheduler can instantiate the class whenever it needs.\n     * </p>\n     */\n    public TriggerEchoJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n        LOG.info(\"TRIGGER: \" + context.getTrigger().getKey());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example15/NativeJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.examples.example15;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p> Built in job for executing native executables in a separate process.</p> \n * \n * <pre>\n *             JobDetail job = new JobDetail(\"dumbJob\", null, org.quartz.jobs.NativeJob.class);\n *             job.getJobDataMap().put(org.quartz.jobs.NativeJob.PROP_COMMAND, \"echo \\\"hi\\\" &gt;&gt; foobar.txt\");\n *             Trigger trigger = TriggerUtils.makeSecondlyTrigger(5);\n *             trigger.setName(\"dumbTrigger\");\n *             sched.scheduleJob(job, trigger);\n * </pre>\n * \n * If PROP_WAIT_FOR_PROCESS is true, then the Integer exit value of the process\n * will be saved as the job execution result in the JobExecutionContext.\n *\n * IMPORTANT SECURITY NOTE: having a class such as this one on your application's classpath, along with a way for\n * users of the application to schedule their own jobs, may provide a security risk of letting users run arbitrary\n * commands on your system.  Take necessary precautions to avoid arbitrary configuring and scheduling of native jobs.\n * \n * @see #PROP_COMMAND\n * @see #PROP_PARAMETERS\n * @see #PROP_WAIT_FOR_PROCESS\n * @see #PROP_CONSUME_STREAMS\n * \n * @author Matthew Payne\n * @author James House\n * @author Steinar Overbeck Cook\n */\npublic class NativeJob implements Job {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constants.\n     *  \n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n        \n    /**\n     * Required parameter that specifies the name of the command (executable) \n     * to be ran.\n     */\n    public static final String PROP_COMMAND = \"command\";\n    \n    /**\n     * Optional parameter that specifies the parameters to be passed to the\n     * executed command.\n     */\n    public static final String PROP_PARAMETERS = \"parameters\";\n    \n    \n    /**\n     * Optional parameter (value should be 'true' or 'false') that specifies \n     * whether the job should wait for the execution of the native process to \n     * complete before it completes.\n     * \n     * <p>Defaults to <code>true</code>.</p>  \n     */\n    public static final String PROP_WAIT_FOR_PROCESS = \"waitForProcess\";\n    \n    /**\n     * Optional parameter (value should be 'true' or 'false') that specifies \n     * whether the spawned process's stdout and stderr streams should be \n     * consumed.  If the process creates output, it is possible that it might\n     * 'hang' if the streams are not consumed.\n     * \n     * <p>Defaults to <code>false</code>.</p>  \n     */\n    public static final String PROP_CONSUME_STREAMS = \"consumeStreams\";\n    \n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        JobDataMap data = context.getMergedJobDataMap();\n        \n        String command = data.getString(PROP_COMMAND);\n\n        String parameters = data.getString(PROP_PARAMETERS);\n\n        if (parameters == null) {\n            parameters = \"\";\n        }\n\n        boolean wait = true;\n        if(data.containsKey(PROP_WAIT_FOR_PROCESS)) {\n            wait = data.getBooleanValue(PROP_WAIT_FOR_PROCESS);\n        }\n        boolean consumeStreams = false;\n        if(data.containsKey(PROP_CONSUME_STREAMS)) {\n            consumeStreams = data.getBooleanValue(PROP_CONSUME_STREAMS);\n        }\n            \n        Integer exitCode = this.runNativeCommand(command, parameters, wait, consumeStreams);\n        context.setResult(exitCode);\n        \n    }\n\n    protected Logger getLog() {\n        return log;\n    }\n    \n    private Integer runNativeCommand(String command, String parameters, boolean wait, boolean consumeStreams) throws JobExecutionException {\n\n        String[] cmd;\n        String[] args = new String[2];\n        Integer  result = null;\n        args[0] = command;\n        args[1] = parameters;\n\n        \n        try {\n            //with this variable will be done the switching\n            String osName = System.getProperty(\"os.name\");\n\n            // specific for Windows\n            if (osName.startsWith(\"Windows\")) {\n                cmd = new String[args.length + 2];\n                if (osName.equals(\"Windows 95\")) { // windows 95 only\n                    cmd[0] = \"command.com\";\n                } else {\n                    cmd[0] = \"cmd.exe\";\n                }\n                cmd[1] = \"/C\";\n                System.arraycopy(args, 0, cmd, 2, args.length);\n            } else if (osName.equals(\"Linux\")) {\n                cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                 cmd[1] = \"-c\";\n                 cmd[2] = args[0] + \" \" + args[1];\n            } else { // try this... \n                cmd = args;\n            }\n\n            Runtime rt = Runtime.getRuntime();\n            // Executes the command\n            getLog().info(\"About to run \" + cmd[0] + \" \" + cmd[1] + \" \" + (cmd.length>2 ? cmd[2] : \"\") + \" ...\"); \n            Process proc = rt.exec(cmd);\n            // Consumes the stdout from the process\n            StreamConsumer stdoutConsumer = new StreamConsumer(proc.getInputStream(), \"stdout\");\n\n            // Consumes the stderr from the process\n            if(consumeStreams) {\n                StreamConsumer stderrConsumer = new StreamConsumer(proc.getErrorStream(), \"stderr\");\n                stdoutConsumer.start();\n                stderrConsumer.start();\n            }\n            \n            if(wait) {\n                result = proc.waitFor();\n            }\n            // any error message?\n            \n        } catch (Throwable x) {\n            throw new JobExecutionException(\"Error launching native command: \", x, false);\n        }\n        \n        return result;\n    }\n\n    /**\n     * Consumes data from the given input stream until EOF and prints the data to stdout\n     *\n     * @author cooste\n     * @author jhouse\n     */\n    class StreamConsumer extends Thread {\n        InputStream is;\n        String type;\n\n        /**\n         *\n         */\n        public StreamConsumer(InputStream inputStream, String type) {\n            this.is = inputStream;\n            this.type = type;\n        }\n\n        /**\n         * Runs this object as a separate thread, printing the contents of the InputStream\n         * supplied during instantiation, to either stdout or stderr\n         */\n        @Override\n        public void run() {\n            BufferedReader br = null;\n            try {\n                br = new BufferedReader(new InputStreamReader(is));\n                String line;\n\n                while ((line = br.readLine()) != null) {\n                    if(type.equalsIgnoreCase(\"stderr\")) {\n                        getLog().warn(type + \">\" + line);\n                    } else {\n                        getLog().info(type + \">\" + line);\n                    }\n                }\n            } catch (IOException ioe) {\n                getLog().error(\"Error consuming \" + type + \" stream of spawned process.\", ioe);\n            } finally {\n                if(br != null) {\n                    try { br.close(); } catch(Exception ignore) {}\n                }\n            }\n        }\n    }\n    \n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example15/NativeJobExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n package org.quartz.examples.example15;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.Trigger;\nimport org.quartz.examples.example14.TriggerEchoJob;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\n/**\n * This Example will demonstrate how run a NativeJob.\n *\n * Please see the note int the NativeJob javadoc about security concerns.\n */\npublic class NativeJobExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(NativeJobExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    JobDetail job = newJob(NativeJob.class).withIdentity(\"MyNativeJob\").build();\n    job.getJobDataMap().put(NativeJob.PROP_COMMAND, \"echo\");\n    job.getJobDataMap().put(NativeJob.PROP_PARAMETERS, \"\\\"ran the native command and captured the stdout.\\\"\");\n    job.getJobDataMap().put(NativeJob.PROP_CONSUME_STREAMS, true);\n\n    // Calculate the start time of all triggers as 5 seconds from now\n    Date startTime = futureDate(5, IntervalUnit.SECOND);\n\n    // First trigger has priority of 1, and will repeat after 5 seconds\n    Trigger trigger1 = newTrigger().withIdentity(\"TriggerWith5SecondRepeat\").startAt(startTime)\n        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)).forJob(job).build();\n\n    // Tell quartz to schedule the job using our trigger\n    sched.scheduleJob(job, trigger1);\n\n    // Start up the scheduler (nothing can actually run until the\n    // scheduler has been started)\n    sched.start();\n    log.info(\"------- Started Scheduler -----------------\");\n\n    // wait long enough so that the scheduler as an opportunity to\n    // fire the triggers\n    log.info(\"------- Waiting 30 seconds... -------------\");\n    try {\n      Thread.sleep(30L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n  }\n\n  public static void main(String[] args) throws Exception {\n    NativeJobExample example = new NativeJobExample();\n    example.run();\n  }\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example2/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example2;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);\n\n    /**\n     * Empty constructor for job initialization\n     */\n    public SimpleJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"SimpleJob says: \" + jobKey + \" executing at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example2/SimpleTriggerExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example2;\n\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.JobKey.jobKey;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.DateBuilder;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This Example will demonstrate all of the basics of scheduling capabilities of Quartz using Simple Triggers.\n * \n * @author Bill Kratzer\n */\npublic class SimpleTriggerExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(SimpleTriggerExample.class);\n\n    log.info(\"------- Initializing -------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete --------\");\n\n    log.info(\"------- Scheduling Jobs ----------------\");\n\n    // jobs can be scheduled before sched.start() has been called\n\n    // get a \"nice round\" time a few seconds in the future...\n    Date startTime = DateBuilder.nextGivenSecondDate(null, 15);\n\n    // job1 will only fire once at date/time \"ts\"\n    JobDetail job = newJob(SimpleJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    SimpleTrigger trigger = (SimpleTrigger) newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(startTime).build();\n\n    // schedule it to run!\n    Date ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job2 will only fire once at date/time \"ts\"\n    job = newJob(SimpleJob.class).withIdentity(\"job2\", \"group1\").build();\n\n    trigger = (SimpleTrigger) newTrigger().withIdentity(\"trigger2\", \"group1\").startAt(startTime).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job3 will run 11 times (run once and repeat 10 more times)\n    // job3 will repeat every 10 seconds\n    job = newJob(SimpleJob.class).withIdentity(\"job3\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger3\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10)).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // the same job (job3) will be scheduled by a another trigger\n    // this time will only repeat twice at a 70 second interval\n\n    trigger = newTrigger().withIdentity(\"trigger3\", \"group2\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(2)).forJob(job).build();\n\n    ft = sched.scheduleJob(trigger);\n    log.info(job.getKey() + \" will [also] run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount()\n             + \" times, every \" + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job4 will run 6 times (run once and repeat 5 more times)\n    // job4 will repeat every 10 seconds\n    job = newJob(SimpleJob.class).withIdentity(\"job4\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger4\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(5)).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job5 will run once, five minutes in the future\n    job = newJob(SimpleJob.class).withIdentity(\"job5\", \"group1\").build();\n\n    trigger = (SimpleTrigger) newTrigger().withIdentity(\"trigger5\", \"group1\")\n        .startAt(futureDate(5, IntervalUnit.MINUTE)).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job6 will run indefinitely, every 40 seconds\n    job = newJob(SimpleJob.class).withIdentity(\"job6\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger6\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(40).repeatForever()).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // All of the jobs have been added to the scheduler, but none of the jobs\n    // will run until the scheduler has been started\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    // jobs can also be scheduled after start() has been called...\n    // job7 will repeat 20 times, repeat every five minutes\n    job = newJob(SimpleJob.class).withIdentity(\"job7\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger7\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInMinutes(5).withRepeatCount(20)).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // jobs can be fired directly... (rather than waiting for a trigger)\n    job = newJob(SimpleJob.class).withIdentity(\"job8\", \"group1\").storeDurably().build();\n\n    sched.addJob(job, true);\n\n    log.info(\"'Manually' triggering job8...\");\n    sched.triggerJob(jobKey(\"job8\", \"group1\"));\n\n    log.info(\"------- Waiting 30 seconds... --------------\");\n\n    try {\n      // wait 33 seconds to show jobs\n      Thread.sleep(30L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // jobs can be re-scheduled...\n    // job 7 will run immediately and repeat 10 times for every second\n    log.info(\"------- Rescheduling... --------------------\");\n    trigger = newTrigger().withIdentity(\"trigger7\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInMinutes(5).withRepeatCount(20)).build();\n\n    ft = sched.rescheduleJob(trigger.getKey(), trigger);\n    log.info(\"job7 rescheduled to run at: \" + ft);\n\n    log.info(\"------- Waiting five minutes... ------------\");\n    try {\n      // wait five minutes to show jobs\n      Thread.sleep(300L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(true);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    // display some stats about the schedule that just ran\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    SimpleTriggerExample example = new SimpleTriggerExample();\n    example.run();\n\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example3/CronTriggerExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example3;\n\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This Example will demonstrate all of the basics of scheduling capabilities of Quartz using Cron Triggers.\n * \n * @author Bill Kratzer\n */\npublic class CronTriggerExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(CronTriggerExample.class);\n\n    log.info(\"------- Initializing -------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete --------\");\n\n    log.info(\"------- Scheduling Jobs ----------------\");\n\n    // jobs can be scheduled before sched.start() has been called\n\n    // job 1 will run every 20 seconds\n    JobDetail job = newJob(SimpleJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    CronTrigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").withSchedule(cronSchedule(\"0/20 * * * * ?\"))\n        .build();\n\n    Date ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 2 will run every other minute (at 15 seconds past the minute)\n    job = newJob(SimpleJob.class).withIdentity(\"job2\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger2\", \"group1\").withSchedule(cronSchedule(\"15 0/2 * * * ?\")).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 3 will run every other minute but only between 8am and 5pm\n    job = newJob(SimpleJob.class).withIdentity(\"job3\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger3\", \"group1\").withSchedule(cronSchedule(\"0 0/2 8-17 * * ?\")).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 4 will run every three minutes but only between 5pm and 11pm\n    job = newJob(SimpleJob.class).withIdentity(\"job4\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger4\", \"group1\").withSchedule(cronSchedule(\"0 0/3 17-23 * * ?\")).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 5 will run at 10am on the 1st and 15th days of the month\n    job = newJob(SimpleJob.class).withIdentity(\"job5\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger5\", \"group1\").withSchedule(cronSchedule(\"0 0 10am 1,15 * ?\")).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 6 will run every 30 seconds but only on Weekdays (Monday through Friday)\n    job = newJob(SimpleJob.class).withIdentity(\"job6\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger6\", \"group1\").withSchedule(cronSchedule(\"0,30 * * ? * MON-FRI\"))\n        .build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    // job 7 will run every 30 seconds but only on Weekends (Saturday and Sunday)\n    job = newJob(SimpleJob.class).withIdentity(\"job7\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger7\", \"group1\").withSchedule(cronSchedule(\"0,30 * * ? * SAT,SUN\"))\n        .build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" has been scheduled to run at: \" + ft + \" and repeat based on expression: \"\n             + trigger.getCronExpression());\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // All of the jobs have been added to the scheduler, but none of the\n    // jobs\n    // will run until the scheduler has been started\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Waiting five minutes... ------------\");\n    try {\n      // wait five minutes to show jobs\n      Thread.sleep(300L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(true);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    CronTriggerExample example = new CronTriggerExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example3/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example3;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);\n\n    /**\n     * Quartz requires a public empty constructor so that the\n     * scheduler can instantiate the class whenever it needs.\n     */\n    public SimpleJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"SimpleJob says: \" + jobKey + \" executing at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example4/ColorJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example4;\n\nimport java.util.Date;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that receives parameters and\n * maintains state\n * </p>\n * \n * @author Bill Kratzer\n */\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic class ColorJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(ColorJob.class);\n    \n    // parameter names specific to this job\n    public static final String FAVORITE_COLOR = \"favorite color\";\n    public static final String EXECUTION_COUNT = \"count\";\n    \n    // Since Quartz will re-instantiate a class every time it\n    // gets executed, members non-static member variables can\n    // not be used to maintain state!\n    private int _counter = 1;\n\n    /**\n     * <p>\n     * Empty constructor for job initialization\n     * </p>\n     * <p>\n     * Quartz requires a public empty constructor so that the\n     * scheduler can instantiate the class whenever it needs.\n     * </p>\n     */\n    public ColorJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        \n        // Grab and print passed parameters\n        JobDataMap data = context.getJobDetail().getJobDataMap();\n        String favoriteColor = data.getString(FAVORITE_COLOR);\n        int count = data.getInt(EXECUTION_COUNT);\n        _log.info(\"ColorJob: \" + jobKey + \" executing at \" + new Date() + \"\\n\" +\n            \"  favorite color is \" + favoriteColor + \"\\n\" + \n            \"  execution count (from job map) is \" + count + \"\\n\" + \n            \"  execution count (from job member variable) is \" + _counter);\n        \n        // increment the count and store it back into the \n        // job map so that job state can be properly maintained\n        count++;\n        data.put(EXECUTION_COUNT, count);\n        \n        // Increment the local member variable \n        // This serves no real purpose since job state can not \n        // be maintained via member variables!\n        _counter++;\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example4/JobStateExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example4;\n\nimport static org.quartz.DateBuilder.nextGivenSecondDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This Example will demonstrate how job parameters can be passed into jobs and how state can be maintained\n * \n * @author Bill Kratzer\n */\npublic class JobStateExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(JobStateExample.class);\n\n    log.info(\"------- Initializing -------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete --------\");\n\n    log.info(\"------- Scheduling Jobs ----------------\");\n\n    // get a \"nice round\" time a few seconds in the future....\n    Date startTime = nextGivenSecondDate(null, 10);\n\n    // job1 will only run 5 times (at start time, plus 4 repeats), every 10 seconds\n    JobDetail job1 = newJob(ColorJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    SimpleTrigger trigger1 = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(4)).build();\n\n    // pass initialization parameters into the job\n    job1.getJobDataMap().put(ColorJob.FAVORITE_COLOR, \"Green\");\n    job1.getJobDataMap().put(ColorJob.EXECUTION_COUNT, 1);\n\n    // schedule the job to run\n    Date scheduleTime1 = sched.scheduleJob(job1, trigger1);\n    log.info(job1.getKey() + \" will run at: \" + scheduleTime1 + \" and repeat: \" + trigger1.getRepeatCount()\n             + \" times, every \" + trigger1.getRepeatInterval() / 1000 + \" seconds\");\n\n    // job2 will also run 5 times, every 10 seconds\n    JobDetail job2 = newJob(ColorJob.class).withIdentity(\"job2\", \"group1\").build();\n\n    SimpleTrigger trigger2 = newTrigger().withIdentity(\"trigger2\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(4)).build();\n\n    // pass initialization parameters into the job\n    // this job has a different favorite color!\n    job2.getJobDataMap().put(ColorJob.FAVORITE_COLOR, \"Red\");\n    job2.getJobDataMap().put(ColorJob.EXECUTION_COUNT, 1);\n\n    // schedule the job to run\n    Date scheduleTime2 = sched.scheduleJob(job2, trigger2);\n    log.info(job2.getKey().toString() + \" will run at: \" + scheduleTime2 + \" and repeat: \" + trigger2.getRepeatCount()\n             + \" times, every \" + trigger2.getRepeatInterval() / 1000 + \" seconds\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // All of the jobs have been added to the scheduler, but none of the jobs\n    // will run until the scheduler has been started\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Waiting 60 seconds... -------------\");\n    try {\n      // wait five minutes to show jobs\n      Thread.sleep(60L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(true);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    JobStateExample example = new JobStateExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example5/MisfireExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example5;\n\nimport static org.quartz.DateBuilder.nextGivenSecondDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * Demonstrates the behavior of <code>StatefulJob</code>s, as well as how misfire instructions affect the firings of\n * triggers of <code>StatefulJob</code> s - when the jobs take longer to execute that the frequency of the trigger's\n * repetition.\n * <p>\n * While the example is running, you should note that there are two triggers with identical schedules, firing identical\n * jobs. The triggers \"want\" to fire every 3 seconds, but the jobs take 10 seconds to execute. Therefore, by the time\n * the jobs complete their execution, the triggers have already \"misfired\" (unless the scheduler's \"misfire threshold\"\n * has been set to more than 7 seconds). You should see that one of the jobs has its misfire instruction set to\n * <code>SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>, which causes it to fire\n * immediately, when the misfire is detected. The other trigger uses the default \"smart policy\" misfire instruction,\n * which causes the trigger to advance to its next fire time (skipping those that it has missed) - so that it does not\n * refire immediately, but rather at the next scheduled time.\n * </p>\n * \n * @author <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n */\npublic class MisfireExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(MisfireExample.class);\n\n    log.info(\"------- Initializing -------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory(\"org/quartz/examples/example5/quartz_misfire.properties\");\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -----------\");\n\n    // jobs can be scheduled before start() has been called\n\n    // get a \"nice round\" time a few seconds in the future...\n    Date startTime = nextGivenSecondDate(null, 15);\n\n    // statefulJob1 will run every three seconds\n    // (but it will delay for ten seconds)\n    JobDetail job = newJob(StatefulDumbJob.class).withIdentity(\"statefulJob1\", \"group1\")\n        .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build();\n\n    SimpleTrigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();\n\n    Date ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // statefulJob2 will run every three seconds\n    // (but it will delay for ten seconds - and therefore purposely misfire after a few iterations)\n    job = newJob(StatefulDumbJob.class).withIdentity(\"statefulJob2\", \"group1\")\n        .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build();\n\n    trigger = newTrigger()\n        .withIdentity(\"trigger2\", \"group1\")\n        .startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()\n                          .withMisfireHandlingInstructionNowWithExistingCount()) // set misfire instructions\n        .build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // jobs don't start firing until start() has been called...\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    try {\n      // sleep for ten minutes for triggers to file....\n      Thread.sleep(600L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(true);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    MisfireExample example = new MisfireExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example5/StatefulDumbJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example5;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.PersistJobDataAfterExecution;\n\nimport java.util.Date;\n\n/**\n * <p>\n * A dumb implementation of Job, for unit testing purposes.\n * </p>\n * \n * @author James House\n */\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic class StatefulDumbJob implements Job {\n\n  /*\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constants.\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   */\n\n  public static final String NUM_EXECUTIONS  = \"NumExecutions\";\n\n  public static final String EXECUTION_DELAY = \"ExecutionDelay\";\n\n  /*\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constructors.\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   */\n\n  public StatefulDumbJob() {\n  }\n\n  /*\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Interface.\n   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   */\n\n  /**\n   * <p>\n   * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code> fires that\n   * is associated with the <code>Job</code>.\n   * </p>\n   * \n   * @throws JobExecutionException if there is an exception while executing the job.\n   */\n  public void execute(JobExecutionContext context) throws JobExecutionException {\n    System.err.println(\"---\" + context.getJobDetail().getKey() + \" executing.[\" + new Date() + \"]\");\n\n    JobDataMap map = context.getJobDetail().getJobDataMap();\n\n    int executeCount = 0;\n    if (map.containsKey(NUM_EXECUTIONS)) {\n      executeCount = map.getInt(NUM_EXECUTIONS);\n    }\n\n    executeCount++;\n\n    map.put(NUM_EXECUTIONS, executeCount);\n\n    long delay = 5000l;\n    if (map.containsKey(EXECUTION_DELAY)) {\n      delay = map.getLong(EXECUTION_DELAY);\n    }\n\n    try {\n      Thread.sleep(delay);\n    } catch (Exception ignore) {\n      //\n    }\n\n    System.err.println(\"  -\" + context.getJobDetail().getKey() + \" complete (\" + executeCount + \").\");\n\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example6/BadJob1.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example6;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * <p>\n * A job dumb job that will throw a job execution exception\n * </p>\n * \n * @author Bill Kratzer\n */\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic class BadJob1 implements Job {\n\n  // Logging\n  private static Logger _log = LoggerFactory.getLogger(BadJob1.class);\n  private int calculation;\n\n  /**\n   * Empty public constructor for job initialization\n   */\n  public BadJob1() {\n  }\n\n  /**\n   * <p>\n   * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code> fires that\n   * is associated with the <code>Job</code>.\n   * </p>\n   * \n   * @throws JobExecutionException if there is an exception while executing the job.\n   */\n  public void execute(JobExecutionContext context) throws JobExecutionException {\n    JobKey jobKey = context.getJobDetail().getKey();\n    JobDataMap dataMap = context.getJobDetail().getJobDataMap();\n\n    int denominator = dataMap.getInt(\"denominator\");\n    _log.info(\"---\" + jobKey + \" executing at \" + new Date() + \" with denominator \" + denominator);\n\n    // a contrived example of an exception that\n    // will be generated by this job due to a\n    // divide by zero error (only on first run)\n    try {\n      calculation = 4815 / denominator;\n    } catch (Exception e) {\n      _log.info(\"--- Error in job!\");\n      JobExecutionException e2 = new JobExecutionException(e);\n\n      // fix denominator so the next time this job run\n      // it won't fail again\n      dataMap.put(\"denominator\", \"1\");\n\n      // this job will refire immediately\n      e2.setRefireImmediately(true);\n      throw e2;\n    }\n\n    _log.info(\"---\" + jobKey + \" completed at \" + new Date());\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example6/BadJob2.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example6;\n\nimport java.util.Date;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * A job dumb job that will throw a job execution exception\n * </p>\n * \n * @author Bill Kratzer\n */\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic class BadJob2 implements Job {\n\n    // Logging\n    private static Logger _log = LoggerFactory.getLogger(BadJob2.class);\n    private int calculation;\n\n    /**\n     * Empty public constructor for job initialization\n     */\n    public BadJob2() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code>\n     * fires that is associated with the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *           if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"---\" + jobKey + \" executing at \" + new Date());\n\n        // a contrived example of an exception that\n        // will be generated by this job due to a \n        // divide by zero error\n        try {\n            int zero = 0;\n            calculation = 4815 / zero;\n        } catch (Exception e) {\n            _log.info(\"--- Error in job!\");\n            JobExecutionException e2 = \n                new JobExecutionException(e);\n            // Quartz will automatically unschedule\n            // all triggers associated with this job\n            // so that it does not run again\n            e2.setUnscheduleAllTriggers(true);\n            throw e2;\n        }\n\n        _log.info(\"---\" + jobKey + \" completed at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example6/JobExceptionExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example6;\n\nimport static org.quartz.DateBuilder.nextGivenSecondDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * This job demonstrates how Quartz can handle JobExecutionExceptions that are thrown by jobs.\n * \n * @author Bill Kratzer\n */\npublic class JobExceptionExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(JobExceptionExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete ------------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    // jobs can be scheduled before start() has been called\n\n    // get a \"nice round\" time a few seconds in the future...\n    Date startTime = nextGivenSecondDate(null, 15);\n\n    // badJob1 will run every 10 seconds\n    // this job will throw an exception and refire\n    // immediately\n    JobDetail job = newJob(BadJob1.class).withIdentity(\"badJob1\", \"group1\").usingJobData(\"denominator\", \"0\").build();\n\n    SimpleTrigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();\n\n    Date ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // badJob2 will run every five seconds\n    // this job will throw an exception and never\n    // refire\n    job = newJob(BadJob2.class).withIdentity(\"badJob2\", \"group1\").build();\n\n    trigger = newTrigger().withIdentity(\"trigger2\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();\n\n    ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    log.info(\"------- Starting Scheduler ----------------\");\n\n    // jobs don't start firing until start() has been called...\n    sched.start();\n\n    log.info(\"------- Started Scheduler -----------------\");\n\n    try {\n      // sleep for 30 seconds\n      Thread.sleep(30L * 1000L);\n    } catch (Exception e) {\n      //\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(false);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    JobExceptionExample example = new JobExceptionExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example7/DumbInterruptableJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example7;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.InterruptableJob;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.UnableToInterruptJobException;\n\n\n/**\n * <p>\n * A dumb implementation of an InterruptableJob, for unit testing purposes.\n * </p>\n * \n * @author <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n * @author Bill Kratzer\n */\npublic class DumbInterruptableJob implements InterruptableJob {\n    \n    // logging services\n    private static Logger _log = LoggerFactory.getLogger(DumbInterruptableJob.class);\n    \n    // has the job been interrupted?\n    private boolean _interrupted = false;\n\n    // job name \n    private JobKey _jobKey = null;\n    \n    /**\n     * <p>\n     * Empty constructor for job initialization\n     * </p>\n     */\n    public DumbInterruptableJob() {\n    }\n\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code>\n     * fires that is associated with the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *           if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        _jobKey = context.getJobDetail().getKey();\n        _log.info(\"---- \" + _jobKey + \" executing at \" + new Date());\n\n        try {\n            // main job loop... see the JavaDOC for InterruptableJob for discussion...\n            // do some work... in this example we are 'simulating' work by sleeping... :)\n\n            for (int i = 0; i < 4; i++) {\n                try {\n                    Thread.sleep(1000L);\n                } catch (Exception ignore) {\n                    ignore.printStackTrace();\n                }\n                \n                // periodically check if we've been interrupted...\n                if(_interrupted) {\n                    _log.info(\"--- \" + _jobKey + \"  -- Interrupted... bailing out!\");\n                    return; // could also choose to throw a JobExecutionException \n                             // if that made for sense based on the particular  \n                             // job's responsibilities/behaviors\n                }\n            }\n            \n        } finally {\n            _log.info(\"---- \" + _jobKey + \" completed at \" + new Date());\n        }\n    }\n    \n    /**\n     * <p>\n     * Called by the Scheduler when a user\n     * interrupts the <code>Job</code>.\n     * </p>\n     *\n     * @throws org.quartz.UnableToInterruptJobException\n     *           if there is an exception while interrupting the job.\n     */\n    public void interrupt() throws UnableToInterruptJobException {\n        _log.info(\"---\" + _jobKey + \"  -- INTERRUPTING --\");\n        _interrupted = true;\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example7/InterruptExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example7;\n\nimport static org.quartz.DateBuilder.nextGivenSecondDate;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * Demonstrates the behavior of <code>StatefulJob</code>s, as well as how misfire instructions affect the firings of\n * triggers of <code>StatefulJob</code> s - when the jobs take longer to execute that the frequency of the trigger's\n * repetition.\n * <p>\n * While the example is running, you should note that there are two triggers with identical schedules, firing identical\n * jobs. The triggers \"want\" to fire every 3 seconds, but the jobs take 10 seconds to execute. Therefore, by the time\n * the jobs complete their execution, the triggers have already \"misfired\" (unless the scheduler's \"misfire threshold\"\n * has been set to more than 7 seconds). You should see that one of the jobs has its misfire instruction set to\n * <code>SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>- which causes it to fire\n * immediately, when the misfire is detected. The other trigger uses the default \"smart policy\" misfire instruction,\n * which causes the trigger to advance to its next fire time (skipping those that it has missed) - so that it does not\n * refire immediately, but rather at the next scheduled time.\n * </p>\n * \n * @author <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n */\npublic class InterruptExample {\n\n  public void run() throws Exception {\n    final Logger log = LoggerFactory.getLogger(InterruptExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    // get a \"nice round\" time a few seconds in the future...\n    Date startTime = nextGivenSecondDate(null, 15);\n\n    JobDetail job = newJob(DumbInterruptableJob.class).withIdentity(\"interruptableJob1\", \"group1\").build();\n\n    SimpleTrigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(startTime)\n        .withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();\n\n    Date ft = sched.scheduleJob(job, trigger);\n    log.info(job.getKey() + \" will run at: \" + ft + \" and repeat: \" + trigger.getRepeatCount() + \" times, every \"\n             + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // start up the scheduler (jobs do not start to fire until\n    // the scheduler has been started)\n    sched.start();\n    log.info(\"------- Started Scheduler -----------------\");\n\n    log.info(\"------- Starting loop to interrupt job every 7 seconds ----------\");\n    for (int i = 0; i < 50; i++) {\n      try {\n        Thread.sleep(7000L);\n        // tell the scheduler to interrupt our job\n        sched.interrupt(job.getKey());\n      } catch (Exception e) {\n        //\n      }\n    }\n\n    log.info(\"------- Shutting Down ---------------------\");\n\n    sched.shutdown(true);\n\n    log.info(\"------- Shutdown Complete -----------------\");\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    InterruptExample example = new InterruptExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example8/CalendarExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example8;\n\nimport static org.quartz.DateBuilder.dateOf;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.examples.example2.SimpleJob;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.calendar.AnnualCalendar;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\n\n/**\n * This example will demonstrate how calendars can be used to exclude periods of time when scheduling should not take\n * place.\n */\npublic class CalendarExample {\n\n  public void run() throws Exception {\n    final Logger log = LoggerFactory.getLogger(CalendarExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    // Add the holiday calendar to the schedule\n    AnnualCalendar holidays = new AnnualCalendar();\n\n    // fourth of July (July 4)\n    Calendar fourthOfJuly = new GregorianCalendar(2005, 6, 4);\n    holidays.setDayExcluded(fourthOfJuly, true);\n    // halloween (Oct 31)\n    Calendar halloween = new GregorianCalendar(2005, 9, 31);\n    holidays.setDayExcluded(halloween, true);\n    // christmas (Dec 25)\n    Calendar christmas = new GregorianCalendar(2005, 11, 25);\n    holidays.setDayExcluded(christmas, true);\n\n    // tell the schedule about our holiday calendar\n    sched.addCalendar(\"holidays\", holidays, false, false);\n\n    // schedule a job to run hourly, starting on halloween\n    // at 10 am\n    Date runDate = dateOf(0, 0, 10, 31, 10);\n\n    JobDetail job = newJob(SimpleJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    SimpleTrigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\").startAt(runDate)\n        .withSchedule(simpleSchedule().withIntervalInHours(1).repeatForever()).modifiedByCalendar(\"holidays\").build();\n\n    // schedule the job and print the first run date\n    Date firstRunTime = sched.scheduleJob(job, trigger);\n\n    // print out the first execution date.\n    // Note: Since Halloween (Oct 31) is a holiday, then\n    // we will not run until the next day! (Nov 1)\n    log.info(job.getKey() + \" will run at: \" + firstRunTime + \" and repeat: \" + trigger.getRepeatCount()\n             + \" times, every \" + trigger.getRepeatInterval() / 1000 + \" seconds\");\n\n    // All of the jobs have been added to the scheduler, but none of the jobs\n    // will run until the scheduler has been started\n    log.info(\"------- Starting Scheduler ----------------\");\n    sched.start();\n\n    // wait 30 seconds:\n    // note: nothing will run\n    log.info(\"------- Waiting 30 seconds... --------------\");\n    try {\n      // wait 30 seconds to show jobs\n      Thread.sleep(30L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    CalendarExample example = new CalendarExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example8/SimpleJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example8;\n\nimport java.util.Date;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);\n\n    /**\n     * Empty constructor for job initialization\n     */\n    public SimpleJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"SimpleJob says: \" + jobKey + \" executing at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example9/Job1Listener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example9;\n\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobListener;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author wkratzer\n */\npublic class Job1Listener implements JobListener {\n\n  private static Logger _log = LoggerFactory.getLogger(Job1Listener.class);\n\n  public String getName() {\n    return \"job1_to_job2\";\n  }\n\n  public void jobToBeExecuted(JobExecutionContext inContext) {\n    _log.info(\"Job1Listener says: Job Is about to be executed.\");\n  }\n\n  public void jobExecutionVetoed(JobExecutionContext inContext) {\n    _log.info(\"Job1Listener says: Job Execution was vetoed.\");\n  }\n\n  public void jobWasExecuted(JobExecutionContext inContext, JobExecutionException inException) {\n    _log.info(\"Job1Listener says: Job was executed.\");\n\n    // Simple job #2\n    JobDetail job2 = newJob(SimpleJob2.class).withIdentity(\"job2\").build();\n\n    Trigger trigger = newTrigger().withIdentity(\"job2Trigger\").startNow().build();\n\n    try {\n      // schedule the job to run!\n      inContext.getScheduler().scheduleJob(job2, trigger);\n    } catch (SchedulerException e) {\n      _log.warn(\"Unable to schedule job2!\");\n      e.printStackTrace();\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example9/ListenerExample.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example9;\n\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobListener;\nimport org.quartz.Matcher;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.matchers.KeyMatcher;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Demonstrates the behavior of <code>JobListener</code>s. In particular, this example will use a job listener to\n * trigger another job after one job successfully executes.\n */\npublic class ListenerExample {\n\n  public void run() throws Exception {\n    Logger log = LoggerFactory.getLogger(ListenerExample.class);\n\n    log.info(\"------- Initializing ----------------------\");\n\n    // First we must get a reference to a scheduler\n    SchedulerFactory sf = new StdSchedulerFactory();\n    Scheduler sched = sf.getScheduler();\n\n    log.info(\"------- Initialization Complete -----------\");\n\n    log.info(\"------- Scheduling Jobs -------------------\");\n\n    // schedule a job to run immediately\n\n    JobDetail job = newJob(SimpleJob1.class).withIdentity(\"job1\").build();\n\n    Trigger trigger = newTrigger().withIdentity(\"trigger1\").startNow().build();\n\n    // Set up the listener\n    JobListener listener = new Job1Listener();\n    Matcher<JobKey> matcher = KeyMatcher.keyEquals(job.getKey());\n    sched.getListenerManager().addJobListener(listener, matcher);\n\n    // schedule the job to run\n    sched.scheduleJob(job, trigger);\n\n    // All of the jobs have been added to the scheduler, but none of the jobs\n    // will run until the scheduler has been started\n    log.info(\"------- Starting Scheduler ----------------\");\n    sched.start();\n\n    // wait 30 seconds:\n    // note: nothing will run\n    log.info(\"------- Waiting 30 seconds... --------------\");\n    try {\n      // wait 30 seconds to show jobs\n      Thread.sleep(30L * 1000L);\n      // executing...\n    } catch (Exception e) {\n      //\n    }\n\n    // shut down the scheduler\n    log.info(\"------- Shutting Down ---------------------\");\n    sched.shutdown(true);\n    log.info(\"------- Shutdown Complete -----------------\");\n\n    SchedulerMetaData metaData = sched.getMetaData();\n    log.info(\"Executed \" + metaData.getNumberOfJobsExecuted() + \" jobs.\");\n\n  }\n\n  public static void main(String[] args) throws Exception {\n\n    ListenerExample example = new ListenerExample();\n    example.run();\n  }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example9/SimpleJob1.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example9;\n\nimport java.util.Date;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob1 implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob1.class);\n\n    /**\n     * Empty constructor for job initialization\n     */\n    public SimpleJob1() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"SimpleJob1 says: \" + jobKey + \" executing at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/java/org/quartz/examples/example9/SimpleJob2.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n \npackage org.quartz.examples.example9;\n\nimport java.util.Date;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that gets fired off many times by example 1\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class SimpleJob2 implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(SimpleJob2.class);\n\n    /**\n     * Empty constructor for job initialization\n     */\n    public SimpleJob2() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with\n     * the <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        // This job simply prints out its job name and the\n        // date and time that it is running\n        JobKey jobKey = context.getJobDetail().getKey();\n        _log.info(\"SimpleJob2 says: \" + jobKey + \" executing at \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "examples/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\n  <appender name=\"default\" class=\"org.apache.log4j.ConsoleAppender\">\n    <param name=\"target\" value=\"System.out\"/>\n    <layout class=\"org.apache.log4j.PatternLayout\">\n      <param name=\"ConversionPattern\" value=\"[%p] %d{dd MMM hh:mm:ss.SSS aa} %t [%c]%n%m%n%n\"/>\n    </layout>\n  </appender>\n\n\n <logger name=\"org.quartz\">\n   <level value=\"info\" />\n </logger>\n\n  <root>\n    <level value=\"info\" />\n    <appender-ref ref=\"default\" />\n  </root>\n\n  \n</log4j:configuration>\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example10/quartz.properties",
    "content": "\n#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: Example10Scheduler\norg.quartz.scheduler.instanceId: AUTO\n\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 3\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n\n#============================================================================\n# Configure Plugins \n#============================================================================\n\norg.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin\n\norg.quartz.plugin.jobInitializer.class: org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin\norg.quartz.plugin.jobInitializer.fileNames: org/quartz/examples/example10/quartz_data.xml\norg.quartz.plugin.jobInitializer.failOnFileNotFound: true\norg.quartz.plugin.jobInitializer.scanInterval: 120\norg.quartz.plugin.jobInitializer.wrapInUserTransaction: false"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example10/quartz_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<job-scheduling-data xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd\"\n    version=\"1.8\">\n    \n    <pre-processing-commands>\n        <delete-jobs-in-group>*</delete-jobs-in-group>  <!-- clear all jobs in scheduler -->\n        <delete-triggers-in-group>*</delete-triggers-in-group> <!-- clear all triggers in scheduler -->\n    </pre-processing-commands>\n    \n    <processing-directives>\n        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), overwrite them -->\n        <overwrite-existing-data>true</overwrite-existing-data>\n        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), and over-write is false, ignore them rather then generating an error -->\n        <ignore-duplicates>false</ignore-duplicates> \n    </processing-directives>\n    \n    <schedule>\n\t    <job>\n\t        <name>TestJob1</name>\n\t        <job-class>org.quartz.examples.example10.SimpleJob</job-class>\n\t    </job>\n\t    \n        <job>\n            <name>TestDurableJob</name>\n            <job-class>org.quartz.examples.example10.SimpleJob</job-class>\n            <durability>true</durability>\n            <recover>false</recover>\n        </job>\n\t    \n\t    <trigger>\n\t        <simple>\n\t            <name>TestSimpleTrigger1AtFiveSecondInterval</name>\n\t            <job-name>TestJob1</job-name>\n\t            <repeat-count>-1</repeat-count> <!-- repeat indefinitely  -->\n\t            <repeat-interval>5000</repeat-interval>  <!--  every 5 seconds -->\n\t        </simple>\n\t    </trigger>\n\t\n\t    <job>\n\t        <name>TestJob2</name>\n\t        <group>GroupOfTestJob2</group>\n\t        <description>This is the description of TestJob2</description>\n\t        <job-class>org.quartz.examples.example10.SimpleJob</job-class>\n\t        <durability>false</durability>\n\t        <recover>true</recover>\n\t        <job-data-map>\n\t            <entry>\n\t                <key>someKey</key>\n\t                <value>someValue</value>\n\t            </entry>\n\t            <entry>\n\t                <key>someOtherKey</key>\n\t                <value>someOtherValue</value>\n\t            </entry>\n\t        </job-data-map>\n\t    </job>\n\t    \n\t    <trigger>\n\t        <simple>\n\t            <name>TestSimpleTrigger2AtTenSecondIntervalAndFiveRepeats</name>\n\t            <group>GroupOfTestJob2Triggers</group>\n\t            <job-name>TestJob2</job-name>\n\t            <job-group>GroupOfTestJob2</job-group>\n\t            <start-time>2010-02-09T10:15:00</start-time>\n\t            <misfire-instruction>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</misfire-instruction>\n\t            <repeat-count>5</repeat-count>\n\t            <repeat-interval>10000</repeat-interval>\n\t        </simple>\n\t    </trigger>\n\t    \n\t    <trigger>\n\t        <cron>\n\t            <name>TestCronTrigger2AtEveryMinute</name>\n\t            <group>GroupOfTestJob2Triggers</group>\n\t            <job-name>TestJob2</job-name>\n\t            <job-group>GroupOfTestJob2</job-group>\n                <job-data-map>\n                    <entry>\n                        <key>someKey</key>\n                        <value>overriddenValue</value>\n                    </entry>\n                    <entry>\n                        <key>someOtherKey</key>\n                        <value>someOtherOverriddenValue</value>\n                    </entry>\n                </job-data-map>\n                <cron-expression>0 * * ? * *</cron-expression>\n\t        </cron>\n\t    </trigger>\n\t\n\t    <trigger>\n\t        <cron>\n\t            <name>TestCronTrigger2AtEveryMinuteOnThe45thSecond</name>\n\t            <group>GroupOfTestJob2Triggers</group>\n\t            <job-name>TestJob2</job-name>\n\t            <job-group>GroupOfTestJob2</job-group>\n\t            <start-time>2010-02-09T12:26:00.0</start-time>\n\t            <end-time>2012-02-09T12:26:00.0</end-time>\n\t            <misfire-instruction>MISFIRE_INSTRUCTION_SMART_POLICY</misfire-instruction>\n\t            <cron-expression>45 * * ? * *</cron-expression>\n\t            <time-zone>America/Los_Angeles</time-zone>\n\t        </cron>\n\t    </trigger>\n    </schedule>    \n</job-scheduling-data>\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example11/quartz.properties",
    "content": "\n#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: TestScheduler\norg.quartz.scheduler.instanceId: AUTO\n\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 15\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example12/client.properties",
    "content": "# Properties file for use by StdSchedulerFactory\n# to create a Quartz Scheduler Instance.\n#\n\n# Configure Main Scheduler Properties  ======================================\n\norg.quartz.scheduler.instanceName: Sched1\norg.quartz.scheduler.logger: schedLogger\norg.quartz.scheduler.rmi.proxy: true\norg.quartz.scheduler.rmi.registryHost: localhost\norg.quartz.scheduler.rmi.registryPort: 1099\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example12/server.properties",
    "content": "#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: Sched1\norg.quartz.scheduler.rmi.export: true\norg.quartz.scheduler.rmi.registryHost: localhost\norg.quartz.scheduler.rmi.registryPort: 1099\norg.quartz.scheduler.rmi.createRegistry: true\n\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 10\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example13/instance1.properties",
    "content": "\n#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: TestScheduler\norg.quartz.scheduler.instanceId: instance_one\n\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 5\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate\norg.quartz.jobStore.useProperties=false\norg.quartz.jobStore.dataSource=myDS\norg.quartz.jobStore.tablePrefix=QRTZ_\norg.quartz.jobStore.isClustered=true\n\n#============================================================================\n# Configure Datasources  \n#============================================================================\n\norg.quartz.dataSource.myDS.driver: org.postgresql.Driver\norg.quartz.dataSource.myDS.URL: jdbc:postgresql://localhost:5432/quartz\norg.quartz.dataSource.myDS.user: quartz\norg.quartz.dataSource.myDS.password: quartz\norg.quartz.dataSource.myDS.maxConnections: 5\norg.quartz.dataSource.myDS.validationQuery: select 0\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example13/instance2.properties",
    "content": "\n#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: TestScheduler\norg.quartz.scheduler.instanceId: instance_two\n\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 5\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate\norg.quartz.jobStore.useProperties=false\norg.quartz.jobStore.dataSource=myDS\norg.quartz.jobStore.tablePrefix=QRTZ_\norg.quartz.jobStore.isClustered=true\n\n#============================================================================\n# Configure Datasources  \n#============================================================================\n\norg.quartz.dataSource.myDS.driver: org.postgresql.Driver\norg.quartz.dataSource.myDS.URL: jdbc:postgresql://localhost:5432/quartz\norg.quartz.dataSource.myDS.user: quartz\norg.quartz.dataSource.myDS.password: quartz\norg.quartz.dataSource.myDS.maxConnections: 5\norg.quartz.dataSource.myDS.validationQuery: select 0\n\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example14/quartz_priority.properties",
    "content": "org.quartz.scheduler.instanceName: PriorityExampleScheduler\n\n# Set thread count to 1 to force Triggers scheduled for the same time to \n# to be ordered by priority.\norg.quartz.threadPool.threadCount: 1\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n"
  },
  {
    "path": "examples/src/main/resources/org/quartz/examples/example5/quartz_misfire.properties",
    "content": "org.quartz.scheduler.instanceName: MisfireExampleScheduler\r\n\r\norg.quartz.threadPool.threadCount: 2\r\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\r\n\r\n# Set misfire threshold to 1 second\r\norg.quartz.jobStore.misfireThreshold: 1000\r\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\r\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.5-bin.zip\nnetworkTimeout=10000\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "\nquartzVersion = 2.5.1-SNAPSHOT\n\nfullname=quartz-scheduler\nname=quartz\nversion=$quartzVersion\n\nslf4jVersion = 2.0.16\nlog4jVersion = 2.24.1\nc3p0Version = 0.10.1\nhikaricpVersion = 5.0.1\n\njbossVersion = 4.0.2\ncommonjVersion = 1.0\n\njunitVersion = 4.13.2\njunitPlatformVersion = 5.11.3\nderbyVersion = 10.15.2.0\ntestcontainersVersion = 1.21.3\n\n# For nexus-publish plugin\nsonatypeUsername = OVERRIDE_ME\nsonatypePassword = OVERRIDE_ME\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\nAPP_HOME=$( cd \"${APP_HOME:-./}\" && pwd -P ) || exit\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n# Collect all arguments for the java command;\n#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of\n#     shell script including quotes and variable substitutions, so put them in\n#     double quotes to make sure that they get re-expanded; and\n#   * put everything else in single quotes, so that it's not re-expanded.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "quartz/build.gradle",
    "content": "plugins {\n    id 'java-library'\n    id 'maven-publish'\n    id 'biz.aQute.bnd.builder'\n}\n\nrepositories {\n    mavenCentral()\n}\n\npublishing {\n    publications {\n        getByName('maven').pom.description = 'Quartz Enterprise Job Scheduler'\n    }\n}\n\ndependencies {\n    compileOnly project(':quartz-stubs')\n\n    implementation \"org.slf4j:slf4j-api:$slf4jVersion\"\n    runtimeOnly \"org.slf4j:slf4j-log4j12:$slf4jVersion\"\n    implementation \"com.mchange:c3p0:$c3p0Version\"\n    implementation \"com.zaxxer:HikariCP:$hikaricpVersion\"\n    compileOnly \"jboss:jboss-common:$jbossVersion\"\n    compileOnly \"jboss:jboss-minimal:$jbossVersion\"\n    compileOnly \"jboss:jboss-system:$jbossVersion\"\n    compileOnly \"jboss:jboss-jmx:$jbossVersion\"\n    compileOnly \"org.apache.geronimo.specs:geronimo-commonj_1.1_spec:$commonjVersion\"\n\n    implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.4'\n\n    compileOnly 'jakarta.transaction:jakarta.transaction-api:2.0.1'\n    testImplementation 'jakarta.transaction:jakarta.transaction-api:2.0.1'\n    compileOnly 'jakarta.servlet:jakarta.servlet-api:6.1.0'\n\n    testImplementation \"org.apache.derby:derby:$derbyVersion\"\n    testImplementation \"org.apache.derby:derbyclient:$derbyVersion\"\n    testImplementation \"org.apache.derby:derbynet:$derbyVersion\"\n    testImplementation 'asm:asm:3.3.1'\n    testImplementation 'org.hamcrest:hamcrest:3.0'\n    testImplementation(platform(\"org.junit:junit-bom:5.11.4\"))\n    testImplementation 'org.junit.jupiter:junit-jupiter-engine'\n    testImplementation 'org.junit.jupiter:junit-jupiter-params'\n    testImplementation 'org.mockito:mockito-core:5.14.2'\n    testImplementation \"org.testcontainers:mssqlserver:$testcontainersVersion\"\n    testImplementation \"org.testcontainers:mariadb:$testcontainersVersion\"\n    testImplementation \"org.testcontainers:postgresql:$testcontainersVersion\"\n    testImplementation 'com.microsoft.sqlserver:mssql-jdbc:13.2.1.jre11'\n    testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.5.7'\n    testImplementation 'org.postgresql:postgresql:42.7.8'\n    testRuntimeOnly(\"org.junit.jupiter:junit-jupiter-engine\")\n}\n\ntest {\n    useJUnitPlatform(){\n        includeEngines(\"junit-jupiter\")\n    }\n    maxParallelForks 1\n    forkEvery 1\n}\n\njava {\n    withJavadocJar()\n    withSourcesJar()\n}\n\njavadoc {\n    options {\n        docTitle = \"Quartz Enterprise Job Scheduler $project.version API\"\n        encoding = 'UTF-8'\n        outputLevel = JavadocOutputLevel.QUIET\n        splitIndex = false\n        author = true;\n        windowTitle = \"Quartz Enterprise Job Scheduler $project.version API\"\n        bottom = 'Copyright IBM Corp. 2024, 2025'\n    }\n}\n\n\nprocessResources {\n    filesMatching('**/quartz-build.properties') {\n        expand([version: project.version, fullname: project.fullname, name: project.name])\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/Calendar.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An interface to be implemented by objects that define spaces of time during \n * which an associated <code>{@link Trigger}</code> may (not) fire. Calendars \n * do not define actual fire times, but rather are used to limit a \n * <code>Trigger</code> from firing on its normal schedule if necessary. Most \n * Calendars include all times by default and allow the user to specify times \n * to exclude. \n * \n * <p>As such, it is often useful to think of Calendars as being used to <I>exclude</I> a block\n * of time - as opposed to <I>include</I> a block of time. (i.e. the \n * schedule &quot;fire every five minutes except on Sundays&quot; could be \n * implemented with a <code>SimpleTrigger</code> and a \n * <code>WeeklyCalendar</code> which excludes Sundays)</p>\n * \n * <p>Implementations MUST take care of being properly <code>Cloneable</code> \n * and <code>Serializable</code>.</p>\n * \n * @author James House\n * @author Juergen Donnerstag\n */\npublic interface Calendar extends java.io.Serializable, java.lang.Cloneable {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    int MONTH = 0;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Set a new base calendar or remove the existing one.\n     * </p>\n     */\n    void setBaseCalendar(Calendar baseCalendar);\n\n    /**\n     * <p>\n     * Get the base calendar. Will be null, if not set.\n     * </p>\n     */\n    Calendar getBaseCalendar();\n\n    /**\n     * <p>\n     * Determine whether the given time (in milliseconds) is 'included' by the\n     * Calendar.\n     * </p>\n     */\n    boolean isTimeIncluded(long timeStamp);\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time.\n     * </p>\n     */\n    long getNextIncludedTime(long timeStamp);\n\n    /**\n     * <p>\n     * Return the description given to the <code>Calendar</code> instance by\n     * its creator (if any).\n     * </p>\n     * \n     * @return null if no description was set.\n     */\n    String getDescription();\n\n    /**\n     * <p>\n     * Set a description for the <code>Calendar</code> instance - may be\n     * useful for remembering/displaying the purpose of the calendar, though\n     * the description has no meaning to Quartz.\n     * </p>\n     */\n    void setDescription(String description);\n    \n    Object clone();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/CalendarIntervalScheduleBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.TimeZone;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.triggers.CalendarIntervalTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\n\n/**\n * <code>CalendarIntervalScheduleBuilder</code> is a {@link ScheduleBuilder} \n * that defines calendar time (day, week, month, year) interval-based \n * schedules for <code>Trigger</code>s.\n *  \n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(withIntervalInDays(3))\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *\n * @see DailyTimeIntervalScheduleBuilder\n * @see CronScheduleBuilder\n * @see ScheduleBuilder\n * @see SimpleScheduleBuilder \n * @see TriggerBuilder\n */\npublic class CalendarIntervalScheduleBuilder extends ScheduleBuilder<CalendarIntervalTrigger> {\n\n    private int interval = 1;\n    private IntervalUnit intervalUnit = IntervalUnit.DAY;\n\n    private int misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_SMART_POLICY;\n    private TimeZone timeZone;\n    private boolean preserveHourOfDayAcrossDaylightSavings;\n    private boolean skipDayIfHourDoesNotExist;\n    \n    protected CalendarIntervalScheduleBuilder() {\n    }\n    \n    /**\n     * Create a CalendarIntervalScheduleBuilder.\n     * \n     * @return the new CalendarIntervalScheduleBuilder\n     */\n    public static CalendarIntervalScheduleBuilder calendarIntervalSchedule() {\n        return new CalendarIntervalScheduleBuilder();\n    }\n    \n    /**\n     * Build the actual Trigger -- NOT intended to be invoked by end users,\n     * but will rather be invoked by a TriggerBuilder which this \n     * ScheduleBuilder is given to.\n     * \n     * @see TriggerBuilder#withSchedule(ScheduleBuilder)\n     */\n    @Override\n    public MutableTrigger build() {\n\n        CalendarIntervalTriggerImpl st = new CalendarIntervalTriggerImpl();\n        st.setRepeatInterval(interval);\n        st.setRepeatIntervalUnit(intervalUnit);\n        st.setMisfireInstruction(misfireInstruction);\n        st.setTimeZone(timeZone);\n        st.setPreserveHourOfDayAcrossDaylightSavings(preserveHourOfDayAcrossDaylightSavings);\n        st.setSkipDayIfHourDoesNotExist(skipDayIfHourDoesNotExist);\n\n        return st;\n    }\n\n    /**\n     * Specify the time unit and interval for the Trigger to be produced.\n     * \n     * @param timeInterval the interval at which the trigger should repeat.\n     * @param unit  the time unit (IntervalUnit) of the interval.  Cannot be less than IntervalUnit.SECOND .\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     * @throws IllegalArgumentException if unit is null or is IntervalUnit.MILLISECOND\n     */\n    public CalendarIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit) {\n        if(unit == null)\n            throw new IllegalArgumentException(\"TimeUnit must be specified.\");\n        if(unit.equals(IntervalUnit.MILLISECOND))\n            throw new IllegalArgumentException(\"TimeUnit cannot be less than SECOND.\");\n\n        validateInterval(timeInterval);\n        this.interval = timeInterval;\n        this.intervalUnit = unit;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.SECOND that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInSeconds the number of seconds at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds) {\n        validateInterval(intervalInSeconds);\n        this.interval = intervalInSeconds;\n        this.intervalUnit = IntervalUnit.SECOND;\n        return this;\n    }\n    \n    /**\n     * Specify an interval in the IntervalUnit.MINUTE that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInMinutes the number of minutes at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes) {\n        validateInterval(intervalInMinutes);\n        this.interval = intervalInMinutes;\n        this.intervalUnit = IntervalUnit.MINUTE;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.HOUR that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInHours the number of hours at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInHours(int intervalInHours) {\n        validateInterval(intervalInHours);\n        this.interval = intervalInHours;\n        this.intervalUnit = IntervalUnit.HOUR;\n        return this;\n    }\n    \n    /**\n     * Specify an interval in the IntervalUnit.DAY that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInDays the number of days at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInDays(int intervalInDays) {\n        validateInterval(intervalInDays);\n        this.interval = intervalInDays;\n        this.intervalUnit = IntervalUnit.DAY;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.WEEK that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInWeeks the number of weeks at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInWeeks(int intervalInWeeks) {\n        validateInterval(intervalInWeeks);\n        this.interval = intervalInWeeks;\n        this.intervalUnit = IntervalUnit.WEEK;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.MONTH that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInMonths the number of months at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInMonths(int intervalInMonths) {\n        validateInterval(intervalInMonths);\n        this.interval = intervalInMonths;\n        this.intervalUnit = IntervalUnit.MONTH;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.YEAR that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInYears the number of years at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getRepeatInterval()\n     * @see CalendarIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public CalendarIntervalScheduleBuilder withIntervalInYears(int intervalInYears) {\n        validateInterval(intervalInYears);\n        this.interval = intervalInYears;\n        this.intervalUnit = IntervalUnit.YEAR;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY} instruction.\n     * \n     * @return the updated CronScheduleBuilder\n     * @see Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY\n     */\n    public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {\n        misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;\n        return this;\n    }\n    \n    /**\n     * If the Trigger misfires, use the \n     * {@link CalendarIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING} instruction.\n     * \n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING\n     */\n    public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing() {\n        misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;\n        return this;\n    }\n    \n    /**\n     * If the Trigger misfires, use the \n     * {@link CalendarIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW} instruction.\n     * \n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\n     */\n    public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed() {\n        misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        return this;\n    }\n    /**\n     * The <code>TimeZone</code> in which to base the schedule.\n     * \n     * @param timezone the time-zone for the schedule.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see CalendarIntervalTrigger#getTimeZone()\n     */\n    public CalendarIntervalScheduleBuilder inTimeZone(TimeZone timezone) {\n        this.timeZone = timezone;\n        return this;\n    }\n    \n    /**\n     * If intervals are a day or greater, this property (set to true) will \n     * cause the firing of the trigger to always occur at the same time of day,\n     * (the time of day of the startTime) regardless of daylight saving time \n     * transitions.  Default value is false.\n     * \n     * <p>\n     * For example, without the property set, your trigger may have a start \n     * time of 9:00 am on March 1st, and a repeat interval of 2 days.  But \n     * after the daylight saving transition occurs, the trigger may start \n     * firing at 8:00 am every other day.\n     * </p>\n     * \n     * <p>\n     * If however, the time of day does not exist on a given day to fire\n     * (e.g. 2:00 am in the United States on the days of daylight saving\n     * transition), the trigger will go ahead and fire one hour off on \n     * that day, and then resume the normal hour on other days.  If\n     * you wish for the trigger to never fire at the \"wrong\" hour, then\n     * you should set the property skipDayIfHourDoesNotExist.\n     * </p>\n     * \n     * @see #skipDayIfHourDoesNotExist(boolean)\n     * @see #inTimeZone(TimeZone)\n     * @see TriggerBuilder#startAt(java.util.Date)\n     */\n    public CalendarIntervalScheduleBuilder preserveHourOfDayAcrossDaylightSavings(boolean preserveHourOfDay) {\n        this.preserveHourOfDayAcrossDaylightSavings = preserveHourOfDay;\n        return this;\n    }\n\n    /**\n     * If intervals are a day or greater, and \n     * preserveHourOfDayAcrossDaylightSavings property is set to true, and the\n     * hour of the day does not exist on a given day for which the trigger \n     * would fire, the day will be skipped and the trigger advanced a second\n     * interval if this property is set to true.  Defaults to false.\n     * \n     * <p>\n     * <b>CAUTION!</b>  If you enable this property, and your hour of day happens \n     * to be that of daylight savings transition (e.g. 2:00 am in the United \n     * States) and the trigger's interval would have had the trigger fire on\n     * that day, then you may actually completely miss a firing on the day of \n     * transition if that hour of day does not exist on that day!  In such a \n     * case the next fire time of the trigger will be computed as double (if \n     * the interval is 2 days, then a span of 4 days between firings will \n     * occur).\n     * </p>\n     * \n     * @see #preserveHourOfDayAcrossDaylightSavings(boolean)\n     */\n    public CalendarIntervalScheduleBuilder skipDayIfHourDoesNotExist(boolean skipDay) {\n        this.skipDayIfHourDoesNotExist = skipDay;\n        return this;\n    }\n    \n    private void validateInterval(int timeInterval) {\n        if(timeInterval <= 0)\n            throw new IllegalArgumentException(\"Interval must be a positive value.\");\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/CalendarIntervalTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.TimeZone;\n\nimport org.quartz.DateBuilder.IntervalUnit;\n\n/**\n * A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * based upon repeating calendar time intervals.\n * \n * <p>The trigger will fire every N (see {@link #getRepeatInterval()} ) units of calendar time\n * (see {@link #getRepeatIntervalUnit()}) as specified in the trigger's definition.\n * This trigger can achieve schedules that are not possible with {@link SimpleTrigger} (e.g \n * because months are not a fixed number of seconds) or {@link CronTrigger} (e.g. because\n * \"every 5 months\" is not an even divisor of 12).</p>\n * \n * <p>If you use an interval unit of <code>MONTH</code> then care should be taken when setting\n * a <code>startTime</code> value that is on a day near the end of the month.  For example,\n * if you choose a start time that occurs on January 31st, and have a trigger with unit\n * <code>MONTH</code> and interval <code>1</code>, then the next fire time will be February 28th, \n * and the next time after that will be March 28th - and essentially each subsequent firing will \n * occur on the 28th of the month, even if a 31st day exists.  If you want a trigger that always\n * fires on the last day of the month - regardless of the number of days in the month, \n * you should use <code>CronTrigger</code>.</p> \n * \n * @see TriggerBuilder\n * @see CalendarIntervalScheduleBuilder\n * @see SimpleScheduleBuilder\n * @see CronScheduleBuilder\n * \n * @author James House\n */\npublic interface CalendarIntervalTrigger extends Trigger {\n\n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link CalendarIntervalTrigger}</code> wants to be \n     * fired now by <code>Scheduler</code>.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;\n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link CalendarIntervalTrigger}</code> wants to have it's\n     * next-fire-time updated to the next time in the schedule after the\n     * current time (taking into account any associated <code>{@link Calendar}</code>,\n     * but it does not want to be fired now.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_DO_NOTHING = 2;\n\n    /**\n     * <p>Get the interval unit - the time unit on with the interval applies.</p>\n     */\n    IntervalUnit getRepeatIntervalUnit();\n\n    /**\n     * <p>\n     * Get the time interval that will be added to the <code>DateIntervalTrigger</code>'s\n     * fire time (in the set repeat interval unit) in order to calculate the time of the \n     * next trigger repeat.\n     * </p>\n     */\n    int getRepeatInterval();\n\n    /**\n     * <p>\n     * Get the number of times the <code>DateIntervalTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    int getTimesTriggered();\n\n    /**\n     * <p>\n     * Gets the time zone within which time calculations related to this \n     * trigger will be performed.\n     * </p>\n     * \n     * <p>\n     * If null, the system default TimeZone will be used.\n     * </p>\n     */\n    TimeZone getTimeZone();\n    \n    \n    /**\n     * If intervals are a day or greater, this property (set to true) will \n     * cause the firing of the trigger to always occur at the same time of day,\n     * (the time of day of the startTime) regardless of daylight saving time \n     * transitions.  Default value is false.\n     * \n     * <p>\n     * For example, without the property set, your trigger may have a start \n     * time of 9:00 am on March 1st, and a repeat interval of 2 days.  But \n     * after the daylight saving transition occurs, the trigger may start \n     * firing at 8:00 am every other day.\n     * </p>\n     * \n     * <p>\n     * If however, the time of day does not exist on a given day to fire\n     * (e.g. 2:00 am in the United States on the days of daylight saving\n     * transition), the trigger will go ahead and fire one hour off on \n     * that day, and then resume the normal hour on other days.  If\n     * you wish for the trigger to never fire at the \"wrong\" hour, then\n     * you should set the property skipDayIfHourDoesNotExist.\n     * </p>\n     * \n     * @see #isSkipDayIfHourDoesNotExist()\n     * @see #getStartTime()\n     * @see #getTimeZone()\n     */\n    boolean isPreserveHourOfDayAcrossDaylightSavings();\n    \n    /**\n     * If intervals are a day or greater, and \n     * preserveHourOfDayAcrossDaylightSavings property is set to true, and the\n     * hour of the day does not exist on a given day for which the trigger \n     * would fire, the day will be skipped and the trigger advanced a second\n     * interval if this property is set to true.  Defaults to false.\n     * \n     * <p>\n     * <b>CAUTION!</b>  If you enable this property, and your hour of day happens \n     * to be that of daylight savings transition (e.g. 2:00 am in the United \n     * States) and the trigger's interval would have had the trigger fire on\n     * that day, then you may actually completely miss a firing on the day of \n     * transition if that hour of day does not exist on that day!  In such a \n     * case the next fire time of the trigger will be computed as double (if \n     * the interval is 2 days, then a span of 4 days between firings will \n     * occur).\n     * </p>\n     * \n     * @see #isPreserveHourOfDayAcrossDaylightSavings()\n     */\n    boolean isSkipDayIfHourDoesNotExist();\n    \n    \n    TriggerBuilder<CalendarIntervalTrigger> getTriggerBuilder();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/CronExpression.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.SortedSet;\nimport java.util.StringTokenizer;\nimport java.util.TimeZone;\nimport java.util.TreeSet;\n\n/**\n * Provides a parser and evaluator for unix-like cron expressions. Cron \n * expressions provide the ability to specify complex time combinations such as\n * &quot;At 8:00am every Monday through Friday&quot; or &quot;At 1:30am every \n * last Friday of the month&quot;. \n * <p>\n * Cron expressions are comprised of 6 required fields and one optional field\n * separated by white space. The fields respectively are described as follows:\n * </p>\n * <table>\n * <caption>Examples of cron expressions and their meanings.</caption>\n * <tr>\n * <th>Field Name</th>\n * <th>&nbsp;</th>\n * <th>Allowed Values</th>\n * <th>&nbsp;</th>\n * <th>Allowed Special Characters</th>\n * </tr>\n * <tr>\n * <td><code>Seconds</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-59</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Minutes</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-59</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Hours</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-23</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Day-of-month</code></td>\n * <td>&nbsp;</td>\n * <td><code>1-31</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * ? / L W</code></td>\n * </tr>\n * <tr>\n * <td><code>Month</code></td>\n * <td>&nbsp;</td>\n * <td><code>1-12 or JAN-DEC</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Day-of-Week</code></td>\n * <td>&nbsp;</td>\n * <td><code>1-7 or SUN-SAT</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * ? / L #</code></td>\n * </tr>\n * <tr>\n * <td><code>Year (Optional)</code></td>\n * <td>&nbsp;</td>\n * <td><code>empty, 1970-2199</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * </table>\n * <p>\n * The '*' character is used to specify all values. For example, &quot;*&quot; \n * in the minute field means &quot;every minute&quot;.\n * </p>\n * <p>\n * The '?' character is allowed for the day-of-month and day-of-week fields. It\n * is used to specify 'no specific value'. This is useful when you need to\n * specify something in one of the two fields, but not the other.\n * <p>\n * The '-' character is used to specify ranges For example &quot;10-12&quot; in\n * the hour field means &quot;the hours 10, 11 and 12&quot;.\n * <p>\n * The ',' character is used to specify additional values. For example\n * &quot;MON,WED,FRI&quot; in the day-of-week field means &quot;the days Monday,\n * Wednesday, and Friday&quot;.\n * </p>\n * <p>\n * The '/' character is used to specify increments. For example &quot;0/15&quot;\n * in the seconds field means &quot;the seconds 0, 15, 30, and 45&quot;. And \n * &quot;5/15&quot; in the seconds field means &quot;the seconds 5, 20, 35, and\n * 50&quot;.  Specifying '*' before the  '/' is equivalent to specifying 0 is\n * the value to start with. Essentially, for each field in the expression, there\n * is a set of numbers that can be turned on or off. For seconds and minutes, \n * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to\n * 31, and for months 0 to 11 (JAN to DEC). The &quot;/&quot; character simply helps you turn\n * on every &quot;nth&quot; value in the given set. Thus &quot;7/6&quot; in the\n * month field only turns on month &quot;7&quot;, it does NOT mean every 6th \n * month, please note that subtlety.  \n * </p>\n * <p>\n * The 'L' character is allowed for the day-of-month and day-of-week fields.\n * This character is short-hand for &quot;last&quot;, but it has different \n * meaning in each of the two fields. For example, the value &quot;L&quot; in \n * the day-of-month field means &quot;the last day of the month&quot; - day 31 \n * for January, day 28 for February on non-leap years. If used in the \n * day-of-week field by itself, it simply means &quot;7&quot; or \n * &quot;SAT&quot;. But if used in the day-of-week field after another value, it\n * means &quot;the last xxx day of the month&quot; - for example &quot;6L&quot;\n * means &quot;the last friday of the month&quot;. You can also specify an offset \n * from the last day of the month, such as \"L-3\" which would mean the third-to-last \n * day of the calendar month. <i>When using the 'L' option, it is important not to \n * specify lists, or ranges of values, as you'll get confusing/unexpected results.</i>\n * </p>\n * <p>\n * The 'W' character is allowed for the day-of-month field.  This character \n * is used to specify the weekday (Monday-Friday) nearest the given day.  As an \n * example, if you were to specify &quot;15W&quot; as the value for the \n * day-of-month field, the meaning is: &quot;the nearest weekday to the 15th of\n * the month&quot;. So if the 15th is a Saturday, the trigger will fire on \n * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the\n * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. \n * However if you specify &quot;1W&quot; as the value for day-of-month, and the\n * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not \n * 'jump' over the boundary of a month's days.  The 'W' character can only be \n * specified when the day-of-month is a single day, not a range or list of days.\n * </p>\n * <p>\n * The 'L' and 'W' characters can also be combined for the day-of-month \n * expression to yield 'LW', which translates to &quot;last weekday of the \n * month&quot;.\n * </p>\n * <p>\n * The '#' character is allowed for the day-of-week field. This character is\n * used to specify &quot;the nth&quot; XXX day of the month. For example, the \n * value of &quot;6#3&quot; in the day-of-week field means the third Friday of \n * the month (day 6 = Friday and &quot;#3&quot; = the 3rd one in the month). \n * Other examples: &quot;2#1&quot; = the first Monday of the month and \n * &quot;4#5&quot; = the fifth Wednesday of the month. Note that if you specify\n * &quot;#5&quot; and there is not 5 of the given day-of-week in the month, then\n * no firing will occur that month.  If the '#' character is used, there can\n * only be one expression in the day-of-week field (&quot;3#1,6#3&quot; is \n * not valid, since there are two expressions).\n * </p>\n * <!--The 'C' character is allowed for the day-of-month and day-of-week fields.\n * This character is short-hand for \"calendar\". This means values are\n * calculated against the associated calendar, if any. If no calendar is\n * associated, then it is equivalent to having an all-inclusive calendar. A\n * value of \"5C\" in the day-of-month field means \"the first day included by the\n * calendar on or after the 5th\". A value of \"1C\" in the day-of-week field\n * means \"the first day included by the calendar on or after Sunday\".-->\n * <p>\n * The legal characters and the names of months and days of the week are not\n * case sensitive.\n * \n * <p>\n * <b>NOTES:</b>\n * </p>\n * <ul>\n * <li>Support for specifying both a day-of-week and a day-of-month value is\n * not complete (you'll need to use the '?' character in one of these fields).\n * </li>\n * <li>Overflowing ranges is supported - that is, having a larger number on \n * the left hand side than the right. You might do 22-2 to catch 10 o'clock \n * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is \n * very important to note that overuse of overflowing ranges creates ranges \n * that don't make sense and no effort has been made to determine which \n * interpretation CronExpression chooses. An example would be \n * \"0 0 14-6 ? * FRI-MON\". </li>\n * </ul>\n * \n * \n * @author Sharada Jambula, James House\n * @author Contributions from Mads Henderson\n * @author Refactoring from CronTrigger to CronExpression by Aaron Craven\n */\npublic final class CronExpression implements Serializable, Cloneable {\n\n    private static final long serialVersionUID = 12423409423L;\n    \n    protected static final int SECOND = 0;\n    protected static final int MINUTE = 1;\n    protected static final int HOUR = 2;\n    protected static final int DAY_OF_MONTH = 3;\n    protected static final int MONTH = 4;\n    protected static final int DAY_OF_WEEK = 5;\n    protected static final int YEAR = 6;\n    protected static final int ALL_SPEC_INT = 99; // '*'\n    protected static final int NO_SPEC_INT = 98; // '?'\n    protected static final int MAX_LAST_DAY_OFFSET = 30;\n    protected static final int LAST_DAY_OFFSET_START = 32; // \"L-30\"\n    protected static final int LAST_DAY_OFFSET_END = LAST_DAY_OFFSET_START + MAX_LAST_DAY_OFFSET; // 'L'\n    protected static final Integer ALL_SPEC = ALL_SPEC_INT;\n    protected static final Integer NO_SPEC = NO_SPEC_INT;\n    \n    protected static final Map<String, Integer> monthMap = new HashMap<>(20);\n    protected static final Map<String, Integer> dayMap = new HashMap<>(60);\n    static {\n        monthMap.put(\"JAN\", 0);\n        monthMap.put(\"FEB\", 1);\n        monthMap.put(\"MAR\", 2);\n        monthMap.put(\"APR\", 3);\n        monthMap.put(\"MAY\", 4);\n        monthMap.put(\"JUN\", 5);\n        monthMap.put(\"JUL\", 6);\n        monthMap.put(\"AUG\", 7);\n        monthMap.put(\"SEP\", 8);\n        monthMap.put(\"OCT\", 9);\n        monthMap.put(\"NOV\", 10);\n        monthMap.put(\"DEC\", 11);\n\n        dayMap.put(\"SUN\", 1);\n        dayMap.put(\"MON\", 2);\n        dayMap.put(\"TUE\", 3);\n        dayMap.put(\"WED\", 4);\n        dayMap.put(\"THU\", 5);\n        dayMap.put(\"FRI\", 6);\n        dayMap.put(\"SAT\", 7);\n    }\n\n    private final String cronExpression;\n    private TimeZone timeZone = null;\n    protected transient TreeSet<Integer> seconds;\n    protected transient TreeSet<Integer> minutes;\n    protected transient TreeSet<Integer> hours;\n    protected transient TreeSet<Integer> daysOfMonth;\n    protected transient TreeSet<Integer> nearestWeekdays;\n    protected transient TreeSet<Integer> months;\n    protected transient TreeSet<Integer> daysOfWeek;\n    protected transient TreeSet<Integer> years;\n\n    protected transient boolean lastDayOfWeek = false;\n    protected transient int nthDayOfWeek = 0;\n    protected transient boolean expressionParsed = false;\n    \n    public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100;\n\n    /**\n     * Constructs a new <CODE>CronExpression</CODE> based on the specified \n     * parameter.\n     * \n     * @param cronExpression String representation of the cron expression the\n     *                       new object should represent\n     * @throws java.text.ParseException\n     *         if the string expression cannot be parsed into a valid \n     *         <CODE>CronExpression</CODE>\n     */\n    public CronExpression(String cronExpression) throws ParseException {\n        if (cronExpression == null) {\n            throw new IllegalArgumentException(\"cronExpression cannot be null\");\n        }\n        \n        this.cronExpression = cronExpression.toUpperCase(Locale.US);\n        \n        buildExpression(this.cronExpression);\n    }\n    \n    /**\n     * Constructs a new {@code CronExpression} as a copy of an existing\n     * instance.\n     * \n     * @param expression\n     *            The existing cron expression to be copied\n     */\n    public CronExpression(CronExpression expression) {\n        /*\n         * We don't call the other constructor here since we need to swallow the\n         * ParseException. We also elide some of the sanity checking as it is\n         * not logically trippable.\n         */\n        this.cronExpression = expression.getCronExpression();\n        try {\n            buildExpression(cronExpression);\n        } catch (ParseException ex) {\n            throw new AssertionError(\"Could not parse expression!\", ex);\n        }\n        if (expression.getTimeZone() != null) {\n            setTimeZone((TimeZone) expression.getTimeZone().clone());\n        }\n    }\n\n    /**\n     * Indicates whether the given date satisfies the cron expression. Note that\n     * milliseconds are ignored, so two Dates falling on different milliseconds\n     * of the same second will always have the same result here.\n     * \n     * @param date the date to evaluate\n     * @return a boolean indicating whether the given date satisfies the cron\n     *         expression\n     */\n    public boolean isSatisfiedBy(Date date) {\n        Calendar testDateCal = Calendar.getInstance(getTimeZone());\n        testDateCal.setTime(date);\n        testDateCal.set(Calendar.MILLISECOND, 0);\n        Date originalDate = testDateCal.getTime();\n        \n        testDateCal.add(Calendar.SECOND, -1);\n        \n        Date timeAfter = getTimeAfter(testDateCal.getTime());\n\n        return ((timeAfter != null) && (timeAfter.equals(originalDate)));\n    }\n    \n    /**\n     * Returns the next date/time <I>after</I> the given date/time which\n     * satisfies the cron expression.\n     * \n     * @param date the date/time at which to begin the search for the next valid\n     *             date/time\n     * @return the next valid date/time\n     */\n    public Date getNextValidTimeAfter(Date date) {\n        return getTimeAfter(date);\n    }\n    \n    /**\n     * Returns the next date/time <I>after</I> the given date/time which does\n     * <I>not</I> satisfy the expression\n     * \n     * @param date the date/time at which to begin the search for the next \n     *             invalid date/time\n     * @return the next valid date/time\n     */\n    public Date getNextInvalidTimeAfter(Date date) {\n        long difference = 1000;\n        \n        //move back to the nearest second so differences will be accurate\n        Calendar adjustCal = Calendar.getInstance(getTimeZone());\n        adjustCal.setTime(date);\n        adjustCal.set(Calendar.MILLISECOND, 0);\n        Date lastDate = adjustCal.getTime();\n        \n        Date newDate;\n        \n        //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution.\n        \n        //keep getting the next included time until it's farther than one second\n        // apart. At that point, lastDate is the last valid fire time. We return\n        // the second immediately following it.\n        while (difference == 1000) {\n            newDate = getTimeAfter(lastDate);\n            if(newDate == null)\n                break;\n            \n            difference = newDate.getTime() - lastDate.getTime();\n            \n            if (difference == 1000) {\n                lastDate = newDate;\n            }\n        }\n        \n        return new Date(lastDate.getTime() + 1000);\n    }\n    \n    /**\n     * Returns the time zone for which this <code>CronExpression</code> \n     * will be resolved.\n     */\n    public TimeZone getTimeZone() {\n        if (timeZone == null) {\n            timeZone = TimeZone.getDefault();\n        }\n\n        return timeZone;\n    }\n\n    /**\n     * Sets the time zone for which  this <code>CronExpression</code> \n     * will be resolved.\n     */\n    public void setTimeZone(TimeZone timeZone) {\n        this.timeZone = timeZone;\n    }\n    \n    /**\n     * Returns the string representation of the <CODE>CronExpression</CODE>\n     * \n     * @return a string representation of the <CODE>CronExpression</CODE>\n     */\n    @Override\n    public String toString() {\n        return cronExpression;\n    }\n\n    /**\n     * Indicates whether the specified cron expression can be parsed into a \n     * valid cron expression\n     * \n     * @param cronExpression the expression to evaluate\n     * @return a boolean indicating whether the given expression is a valid cron\n     *         expression\n     */\n    public static boolean isValidExpression(String cronExpression) {\n        \n        try {\n            new CronExpression(cronExpression);\n        } catch (ParseException pe) {\n            return false;\n        }\n        \n        return true;\n    }\n\n    public static void validateExpression(String cronExpression) throws ParseException {\n        \n        new CronExpression(cronExpression);\n    }\n    \n    \n    ////////////////////////////////////////////////////////////////////////////\n    //\n    // Expression Parsing Functions\n    //\n    ////////////////////////////////////////////////////////////////////////////\n\n    protected void buildExpression(String expression) throws ParseException {\n        expressionParsed = true;\n\n        try {\n\n            if (seconds == null) {\n                seconds = new TreeSet<>();\n            }\n            if (minutes == null) {\n                minutes = new TreeSet<>();\n            }\n            if (hours == null) {\n                hours = new TreeSet<>();\n            }\n            if (daysOfMonth == null) {\n                daysOfMonth = new TreeSet<>();\n            }\n            if (nearestWeekdays == null) {\n                nearestWeekdays = new TreeSet<>();\n            }\n            if (months == null) {\n                months = new TreeSet<>();\n            }\n            if (daysOfWeek == null) {\n                daysOfWeek = new TreeSet<>();\n            }\n            if (years == null) {\n                years = new TreeSet<>();\n            }\n\n            int exprOn = SECOND;\n\n            StringTokenizer exprsTok = new StringTokenizer(expression, \" \\t\",\n                    false);\n\n            if(exprsTok.countTokens() > 7) {\n                throw new ParseException(\"Invalid expression has too many terms: \" + expression, -1);\n            }\n\n            while (exprsTok.hasMoreTokens() && exprOn <= YEAR) {\n                String expr = exprsTok.nextToken().trim();\n\n                // throw an exception if L is used with other days of the week\n                if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1  && expr.contains(\",\")) {\n                    throw new ParseException(\"Support for specifying 'L' with other days of the week is not implemented\", -1);\n                }\n                if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) {\n                    throw new ParseException(\"Support for specifying multiple \\\"nth\\\" days is not implemented.\", -1);\n                }\n                \n                StringTokenizer vTok = new StringTokenizer(expr, \",\");\n                while (vTok.hasMoreTokens()) {\n                    String v = vTok.nextToken();\n                    storeExpressionVals(0, v, exprOn);\n                }\n\n                exprOn++;\n            }\n\n            if (exprOn <= DAY_OF_WEEK) {\n                throw new ParseException(\"Unexpected end of expression.\",\n                            expression.length());\n            }\n\n            if (exprOn <= YEAR) {\n                storeExpressionVals(0, \"*\", YEAR);\n            }\n\n            TreeSet<Integer> dow = getSet(DAY_OF_WEEK);\n            TreeSet<Integer> dom = getSet(DAY_OF_MONTH);\n\n            // Copying the logic from the UnsupportedOperationException below\n            boolean dayOfMSpec = !dom.contains(NO_SPEC);\n            boolean dayOfWSpec = !dow.contains(NO_SPEC);\n\n            if (!dayOfMSpec || dayOfWSpec) {\n                if (!dayOfWSpec || dayOfMSpec) {\n                    throw new ParseException(\n                            \"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\", 0);\n                }\n            }\n        } catch (ParseException pe) {\n            throw pe;\n        } catch (Exception e) {\n            throw new ParseException(\"Illegal cron expression format (\"\n                    + e + \")\", 0);\n        }\n    }\n\n    protected int storeExpressionVals(int pos, String s, int type)\n        throws ParseException {\n\n        int incr = 0;\n        int i = skipWhiteSpace(pos, s);\n        if (i >= s.length()) {\n            return i;\n        }\n        char c = s.charAt(i);\n        if ((c >= 'A') && (c <= 'Z') && (!s.equals(\"L\")) && (!s.equals(\"LW\")) && (!s.matches(\"^L-[0-9]*[W]?\"))) {\n            String sub = s.substring(i, i + 3);\n            int sval = -1;\n            int eval = -1;\n            if (type == MONTH) {\n                sval = getMonthNumber(sub) + 1;\n                if (sval <= 0) {\n                    throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                }\n                if (s.length() > i + 3) {\n                    c = s.charAt(i + 3);\n                    if (c == '-') {\n                        i += 4;\n                        sub = s.substring(i, i + 3);\n                        eval = getMonthNumber(sub) + 1;\n                        if (eval <= 0) {\n                            throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                        }\n                    }\n                }\n            } else if (type == DAY_OF_WEEK) {\n                sval = getDayOfWeekNumber(sub);\n                if (sval < 0) {\n                    throw new ParseException(\"Invalid Day-of-Week value: '\"\n                                + sub + \"'\", i);\n                }\n                if (s.length() > i + 3) {\n                    c = s.charAt(i + 3);\n                    if (c == '-') {\n                        i += 4;\n                        sub = s.substring(i, i + 3);\n                        eval = getDayOfWeekNumber(sub);\n                        if (eval < 0) {\n                            throw new ParseException(\n                                    \"Invalid Day-of-Week value: '\" + sub\n                                        + \"'\", i);\n                        }\n                    } else if (c == '#') {\n                        try {\n                            i += 4;\n                            nthDayOfWeek = Integer.parseInt(s.substring(i));\n                            if (nthDayOfWeek < 1 || nthDayOfWeek > 5) {\n                                throw new Exception();\n                            }\n                        } catch (Exception e) {\n                            throw new ParseException(\n                                    \"A numeric value between 1 and 5 must follow the '#' option\",\n                                    i);\n                        }\n                    } else if (c == 'L') {\n                        lastDayOfWeek = true;\n                        i++;\n                    }\n                }\n\n            } else {\n                throw new ParseException(\n                        \"Illegal characters for this position: '\" + sub + \"'\",\n                        i);\n            }\n            if (eval != -1) {\n                incr = 1;\n            }\n            addToSet(sval, eval, incr, type);\n            return (i + 3);\n        }\n\n        if (c == '?') {\n            i++;\n            if ((i + 1) < s.length() \n                    && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\\t')) {\n                throw new ParseException(\"Illegal character after '?': \"\n                            + s.charAt(i), i);\n            }\n            if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {\n                throw new ParseException(\n                            \"'?' can only be specified for Day-of-Month or Day-of-Week.\",\n                            i);\n            }\n            if (type == DAY_OF_WEEK) {\n                if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) {\n                    throw new ParseException(\n                                \"'?' can only be specified for Day-of-Month -OR- Day-of-Week.\",\n                                i);\n                }\n            }\n\n            addToSet(NO_SPEC_INT, -1, 0, type);\n            return i;\n        }\n\n        if (c == '*' || c == '/') {\n            if (c == '*' && (i + 1) >= s.length()) {\n                addToSet(ALL_SPEC_INT, -1, incr, type);\n                return i + 1;\n            } else if (c == '/'\n                    && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s\n                            .charAt(i + 1) == '\\t')) { \n                throw new ParseException(\"'/' must be followed by an integer.\", i);\n            } else if (c == '*') {\n                i++;\n            }\n            c = s.charAt(i);\n            if (c == '/') { // is an increment specified?\n                i++;\n                if (i >= s.length()) {\n                    throw new ParseException(\"Unexpected end of string.\", i);\n                }\n\n                incr = getNumericValue(s, i);\n\n                i++;\n                if (incr > 10) {\n                    i++;\n                }\n                checkIncrementRange(incr, type, i);\n            } else {\n                incr = 1;\n            }\n\n            addToSet(ALL_SPEC_INT, -1, incr, type);\n            return i;\n        } else if (c == 'L') {\n\n            if(type < DAY_OF_MONTH)\n                throw new ParseException(\"'L' not expected in seconds, minutes or hours fields.\", i);\n\n            i++;\n            if (type == DAY_OF_WEEK) {\n                addToSet(7, 7, 0, type);\n            }\n            if (type == DAY_OF_MONTH) {\n                int dom = LAST_DAY_OFFSET_END;\n                boolean nearestWeekday = false;\n                if (s.length() > i) {\n                    c = s.charAt(i);\n                    if (c == '-') {\n                        ValueSet vs = getValue(0, s, i + 1);\n                        int offset = vs.value;\n                        if (offset > MAX_LAST_DAY_OFFSET)\n                            throw new ParseException(\"Offset from last day must be <= \" + MAX_LAST_DAY_OFFSET, i + 1);\n                        dom -= offset;\n                        i = vs.pos;\n                    }\n                    if (s.length() > i) {\n                        c = s.charAt(i);\n                        if (c == 'W') {\n                            nearestWeekday = true;\n                            i++;\n                        }\n                    }\n                }\n                if (nearestWeekday) {\n                    nearestWeekdays.add(dom);\n                } else {\n                    daysOfMonth.add(dom);\n                }\n            }\n            return i;\n        } else if (c >= '0' && c <= '9') {\n            int val = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                addToSet(val, -1, -1, type);\n            } else {\n                c = s.charAt(i);\n                if (c >= '0' && c <= '9') {\n                    ValueSet vs = getValue(val, s, i);\n                    val = vs.value;\n                    i = vs.pos;\n                }\n                i = checkNext(i, s, val, type);\n                return i;\n            }\n        } else {\n            throw new ParseException(\"Unexpected character: \" + c, i);\n        }\n\n        return i;\n    }\n\n    private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException {\n        if (incr > 59 && (type == SECOND || type == MINUTE)) {\n            throw new ParseException(\"Increment >= 60 : \" + incr, idxPos);\n        } else if (incr > 23 && (type == HOUR)) {\n            throw new ParseException(\"Increment >= 24 : \" + incr, idxPos);\n        } else if (incr > 31 && (type == DAY_OF_MONTH)) {\n            throw new ParseException(\"Increment >= 31 : \" + incr, idxPos);\n        } else if (incr > 7 && (type == DAY_OF_WEEK)) {\n            throw new ParseException(\"Increment >= 7 : \" + incr, idxPos);\n        } else if (incr > 12 && (type == MONTH)) {\n            throw new ParseException(\"Increment >= 12 : \" + incr, idxPos);\n        }\n    }\n\n    protected int checkNext(int pos, String s, int val, int type)\n        throws ParseException {\n        \n        int end = -1;\n        int i = pos;\n\n        if (i >= s.length()) {\n            addToSet(val, end, -1, type);\n            return i;\n        }\n\n        char c = s.charAt(pos);\n\n        if (c == 'L') {\n            if (type == DAY_OF_WEEK) {\n                if(val < 1 || val > 7)\n                    throw new ParseException(\"Day-of-Week values must be between 1 and 7\", -1);\n                lastDayOfWeek = true;\n            } else {\n                throw new ParseException(\"'L' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            TreeSet<Integer> set = getSet(type);\n            set.add(val);\n            i++;\n            return i;\n        }\n        \n        if (c == 'W') {\n            if (type != DAY_OF_MONTH) {\n                throw new ParseException(\"'W' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            if(val > 31)\n                throw new ParseException(\"The 'W' option does not make sense with values larger than 31 (max number of days in a month)\", i);\n            nearestWeekdays.add(val);\n            i++;\n            return i;\n        }\n\n        if (c == '#') {\n            if (type != DAY_OF_WEEK) {\n                throw new ParseException(\"'#' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            i++;\n            try {\n                nthDayOfWeek = Integer.parseInt(s.substring(i));\n                if (nthDayOfWeek < 1 || nthDayOfWeek > 5) {\n                    throw new Exception();\n                }\n            } catch (Exception e) {\n                throw new ParseException(\n                        \"A numeric value between 1 and 5 must follow the '#' option\",\n                        i);\n            }\n\n            TreeSet<Integer> set = getSet(type);\n            set.add(val);\n            i++;\n            return i;\n        }\n\n        if (c == '-') {\n            i++;\n            c = s.charAt(i);\n            int v = Integer.parseInt(String.valueOf(c));\n            end = v;\n            i++;\n            if (i >= s.length()) {\n                addToSet(val, end, 1, type);\n                return i;\n            }\n            c = s.charAt(i);\n            if (c >= '0' && c <= '9') {\n                ValueSet vs = getValue(v, s, i);\n                end = vs.value;\n                i = vs.pos;\n            }\n            if (i < s.length() && ((c = s.charAt(i)) == '/')) {\n                i++;\n                c = s.charAt(i);\n                int v2 = Integer.parseInt(String.valueOf(c));\n                i++;\n                if (i >= s.length()) {\n                    addToSet(val, end, v2, type);\n                    return i;\n                }\n                c = s.charAt(i);\n                if (c >= '0' && c <= '9') {\n                    ValueSet vs = getValue(v2, s, i);\n                    int v3 = vs.value;\n                    addToSet(val, end, v3, type);\n                    i = vs.pos;\n                    return i;\n                } else {\n                    addToSet(val, end, v2, type);\n                    return i;\n                }\n            } else {\n                addToSet(val, end, 1, type);\n                return i;\n            }\n        }\n\n        if (c == '/') {\n            if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\\t') {\n                throw new ParseException(\"'/' must be followed by an integer.\", i);\n            }\n\n            i++;\n            c = s.charAt(i);\n            int v2 = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                checkIncrementRange(v2, type, i);\n                addToSet(val, end, v2, type);\n                return i;\n            }\n            c = s.charAt(i);\n            if (c >= '0' && c <= '9') {\n                ValueSet vs = getValue(v2, s, i);\n                int v3 = vs.value;\n                checkIncrementRange(v3, type, i);\n                addToSet(val, end, v3, type);\n                i = vs.pos;\n                return i;\n            } else {\n                throw new ParseException(\"Unexpected character '\" + c + \"' after '/'\", i);\n            }\n        }\n\n        addToSet(val, end, 0, type);\n        i++;\n        return i;\n    }\n\n    public String getCronExpression() {\n        return cronExpression;\n    }\n    \n    public String getExpressionSummary() {\n        StringBuilder buf = new StringBuilder();\n\n        buf.append(\"seconds: \");\n        buf.append(getExpressionSetSummary(seconds));\n        buf.append(\"\\n\");\n        buf.append(\"minutes: \");\n        buf.append(getExpressionSetSummary(minutes));\n        buf.append(\"\\n\");\n        buf.append(\"hours: \");\n        buf.append(getExpressionSetSummary(hours));\n        buf.append(\"\\n\");\n        buf.append(\"daysOfMonth: \");\n        buf.append(getExpressionSetSummary(daysOfMonth));\n        buf.append(\"\\n\");\n        buf.append(\"nearestWeekdays: \");\n        buf.append(getExpressionSetSummary(nearestWeekdays));\n        buf.append(\"\\n\");\n        buf.append(\"months: \");\n        buf.append(getExpressionSetSummary(months));\n        buf.append(\"\\n\");\n        buf.append(\"daysOfWeek: \");\n        buf.append(getExpressionSetSummary(daysOfWeek));\n        buf.append(\"\\n\");\n        buf.append(\"lastDayOfWeek: \");\n        buf.append(lastDayOfWeek);\n        buf.append(\"\\n\");\n        buf.append(\"NthDayOfWeek: \");\n        buf.append(nthDayOfWeek);\n        buf.append(\"\\n\");\n        buf.append(\"years: \");\n        buf.append(getExpressionSetSummary(years));\n        buf.append(\"\\n\");\n\n        return buf.toString();\n    }\n\n    protected String getExpressionSetSummary(java.util.Set<Integer> set) {\n\n        if (set.contains(NO_SPEC)) {\n            return \"?\";\n        }\n        if (set.contains(ALL_SPEC)) {\n            return \"*\";\n        }\n\n        StringBuilder buf = new StringBuilder();\n\n        Iterator<Integer> itr = set.iterator();\n        boolean first = true;\n        while (itr.hasNext()) {\n            Integer iVal = itr.next();\n            String val = iVal.toString();\n            if (!first) {\n                buf.append(\",\");\n            }\n            buf.append(val);\n            first = false;\n        }\n\n        return buf.toString();\n    }\n\n    protected String getExpressionSetSummary(java.util.ArrayList<Integer> list) {\n\n        if (list.contains(NO_SPEC)) {\n            return \"?\";\n        }\n        if (list.contains(ALL_SPEC)) {\n            return \"*\";\n        }\n\n        StringBuilder buf = new StringBuilder();\n\n        Iterator<Integer> itr = list.iterator();\n        boolean first = true;\n        while (itr.hasNext()) {\n            Integer iVal = itr.next();\n            String val = iVal.toString();\n            if (!first) {\n                buf.append(\",\");\n            }\n            buf.append(val);\n            first = false;\n        }\n\n        return buf.toString();\n    }\n\n    protected int skipWhiteSpace(int i, String s) {\n        for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\\t'); i++) {\n        }\n\n        return i;\n    }\n\n    protected int findNextWhiteSpace(int i, String s) {\n        for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\\t'); i++) {\n        }\n\n        return i;\n    }\n\n    protected void addToSet(int val, int end, int incr, int type)\n        throws ParseException {\n        \n        TreeSet<Integer> set = getSet(type);\n\n        if (type == SECOND || type == MINUTE) {\n            if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Minute and Second values must be between 0 and 59\",\n                        -1);\n            }\n        } else if (type == HOUR) {\n            if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Hour values must be between 0 and 23\", -1);\n            }\n        } else if (type == DAY_OF_MONTH) {\n            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) \n                    && (val != NO_SPEC_INT)) {\n                throw new ParseException(\n                        \"Day of month values must be between 1 and 31\", -1);\n            }\n        } else if (type == MONTH) {\n            if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Month values must be between 1 and 12\", -1);\n            }\n        } else if (type == DAY_OF_WEEK) {\n            if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT)\n                    && (val != NO_SPEC_INT)) {\n                throw new ParseException(\n                        \"Day-of-Week values must be between 1 and 7\", -1);\n            }\n        }\n\n        if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {\n            if (val != -1) {\n                set.add(val);\n            } else {\n                set.add(NO_SPEC);\n            }\n            \n            return;\n        }\n\n        int startAt = val;\n        int stopAt = end;\n\n        if (val == ALL_SPEC_INT && incr <= 0) {\n            incr = 1;\n            set.add(ALL_SPEC); // put in a marker, but also fill values\n        }\n\n        if (type == SECOND || type == MINUTE) {\n            if (stopAt == -1) {\n                stopAt = 59;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 0;\n            }\n        } else if (type == HOUR) {\n            if (stopAt == -1) {\n                stopAt = 23;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 0;\n            }\n        } else if (type == DAY_OF_MONTH) {\n            if (stopAt == -1) {\n                stopAt = 31;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == MONTH) {\n            if (stopAt == -1) {\n                stopAt = 12;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == DAY_OF_WEEK) {\n            if (stopAt == -1) {\n                stopAt = 7;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == YEAR) {\n            if (stopAt == -1) {\n                stopAt = MAX_YEAR;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1970;\n            }\n        }\n\n        // if the end of the range is before the start, then we need to overflow into \n        // the next day, month etc. This is done by adding the maximum amount for that \n        // type, and using modulus max to determine the value being added.\n        int max = -1;\n        if (stopAt < startAt) {\n            switch (type) {\n              case       SECOND : max = 60; break;\n              case       MINUTE : max = 60; break;\n              case         HOUR : max = 24; break;\n              case        MONTH : max = 12; break;\n              case  DAY_OF_WEEK : max = 7;  break;\n              case DAY_OF_MONTH : max = 31; break;\n              case         YEAR : throw new IllegalArgumentException(\"Start year must be less than stop year\");\n              default           : throw new IllegalArgumentException(\"Unexpected type encountered\");\n            }\n            stopAt += max;\n        }\n\n        for (int i = startAt; i <= stopAt; i += incr) {\n            if (max == -1) {\n                // ie: there's no max to overflow over\n                set.add(i);\n            } else {\n                // take the modulus to get the real value\n                int i2 = i % max;\n\n                // 1-indexed ranges should not include 0, and should include their max\n                if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) {\n                    i2 = max;\n                }\n\n                set.add(i2);\n            }\n        }\n    }\n\n    TreeSet<Integer> getSet(int type) {\n        switch (type) {\n            case SECOND:\n                return seconds;\n            case MINUTE:\n                return minutes;\n            case HOUR:\n                return hours;\n            case DAY_OF_MONTH:\n                return daysOfMonth;\n            case MONTH:\n                return months;\n            case DAY_OF_WEEK:\n                return daysOfWeek;\n            case YEAR:\n                return years;\n            default:\n                return null;\n        }\n    }\n\n    protected ValueSet getValue(int v, String s, int i) {\n        char c = s.charAt(i);\n        StringBuilder s1 = new StringBuilder(String.valueOf(v));\n        while (c >= '0' && c <= '9') {\n            s1.append(c);\n            i++;\n            if (i >= s.length()) {\n                break;\n            }\n            c = s.charAt(i);\n        }\n        ValueSet val = new ValueSet();\n        \n        val.pos = (i < s.length()) ? i : i + 1;\n        val.value = Integer.parseInt(s1.toString());\n        return val;\n    }\n\n    protected int getNumericValue(String s, int i) {\n        int endOfVal = findNextWhiteSpace(i, s);\n        String val = s.substring(i, endOfVal);\n        return Integer.parseInt(val);\n    }\n\n    protected int getMonthNumber(String s) {\n        Integer integer = monthMap.get(s);\n\n        if (integer == null) {\n            return -1;\n        }\n\n        return integer;\n    }\n\n    protected int getDayOfWeekNumber(String s) {\n        Integer integer = dayMap.get(s);\n\n        if (integer == null) {\n            return -1;\n        }\n\n        return integer;\n    }\n\n    ////////////////////////////////////////////////////////////////////////////\n    //\n    // Computation Functions\n    //\n    ////////////////////////////////////////////////////////////////////////////\n\n    public Date getTimeAfter(Date afterTime) {\n\n        // Computation is based on Gregorian year only.\n        Calendar cl = new java.util.GregorianCalendar(getTimeZone()); \n\n        // move ahead one second, since we're computing the time *after* the\n        // given time\n        afterTime = new Date(afterTime.getTime() + 1000);\n        // CronTrigger does not deal with milliseconds\n        cl.setTime(afterTime);\n        cl.set(Calendar.MILLISECOND, 0);\n\n        boolean gotOne = false;\n        // loop until we've computed the next time, or we've past the endTime\n        while (!gotOne) {\n\n            //if (endTime != null && cl.getTime().after(endTime)) return null;\n            if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop...\n                return null;\n            }\n\n            SortedSet<Integer> st = null;\n            int t = 0;\n\n            int sec = cl.get(Calendar.SECOND);\n            int min = cl.get(Calendar.MINUTE);\n\n            // get second.................................................\n            st = seconds.tailSet(sec);\n            if (st != null && !st.isEmpty()) {\n                sec = st.first();\n            } else {\n                sec = seconds.first();\n                min++;\n                cl.set(Calendar.MINUTE, min);\n            }\n            cl.set(Calendar.SECOND, sec);\n\n            min = cl.get(Calendar.MINUTE);\n            int hr = cl.get(Calendar.HOUR_OF_DAY);\n            t = -1;\n\n            // get minute.................................................\n            st = minutes.tailSet(min);\n            if (st != null && !st.isEmpty()) {\n                t = min;\n                min = st.first();\n            } else {\n                min = minutes.first();\n                hr++;\n            }\n            if (min != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, min);\n                setCalendarHour(cl, hr);\n                continue;\n            }\n            cl.set(Calendar.MINUTE, min);\n\n            hr = cl.get(Calendar.HOUR_OF_DAY);\n            int day = cl.get(Calendar.DAY_OF_MONTH);\n            t = -1;\n\n            // get hour...................................................\n            st = hours.tailSet(hr);\n            if (st != null && !st.isEmpty()) {\n                t = hr;\n                hr = st.first();\n            } else {\n                hr = hours.first();\n                day++;\n            }\n            if (hr != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.DAY_OF_MONTH, day);\n                setCalendarHour(cl, hr);\n                continue;\n            }\n            cl.set(Calendar.HOUR_OF_DAY, hr);\n\n            day = cl.get(Calendar.DAY_OF_MONTH);\n            int mon = cl.get(Calendar.MONTH) + 1;\n            // '+ 1' because calendar is 0-based for this field, and we are\n            // 1-based\n            t = -1;\n            int tmon = mon;\n            \n            // get day...................................................\n            boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC);\n            boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC);\n            if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule\n                Optional<Integer> smallestDay = findSmallestDay(day, mon, cl.get(Calendar.YEAR), daysOfMonth);\n                Optional<Integer> smallestDayForWeekday = findSmallestDay(day, mon, cl.get(Calendar.YEAR), nearestWeekdays);\n                t = day;\n                day = -1;\n                if (smallestDayForWeekday.isPresent()) {\n                    day = smallestDayForWeekday.get();\n\n                    java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());\n                    tcal.set(Calendar.SECOND, 0);\n                    tcal.set(Calendar.MINUTE, 0);\n                    tcal.set(Calendar.HOUR_OF_DAY, 0);\n                    tcal.set(Calendar.DAY_OF_MONTH, day);\n                    tcal.set(Calendar.MONTH, mon - 1);\n                    tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));\n                    \n                    int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n                    int dow = tcal.get(Calendar.DAY_OF_WEEK);\n\n                    if(dow == Calendar.SATURDAY && day == 1) {\n                        day += 2;\n                    } else if(dow == Calendar.SATURDAY) {\n                        day -= 1;\n                    } else if(dow == Calendar.SUNDAY && day == ldom) { \n                        day -= 2;\n                    } else if(dow == Calendar.SUNDAY) { \n                        day += 1;\n                    }\n                        \n                \n                    tcal.set(Calendar.SECOND, sec);\n                    tcal.set(Calendar.MINUTE, min);\n                    tcal.set(Calendar.HOUR_OF_DAY, hr);\n                    tcal.set(Calendar.DAY_OF_MONTH, day);\n                    tcal.set(Calendar.MONTH, mon - 1);\n                    Date nTime = tcal.getTime();\n                    if(nTime.before(afterTime)) {\n                        day = -1;\n                    }\n                }\n\n                boolean needAdvance = false;\n                if (smallestDay.isPresent()) {\n                    if (day == -1 || smallestDay.get() < day) {\n                        day = smallestDay.get();\n                        needAdvance = true;\n                    }\n                } else if (day == -1) {\n                    day = 1;\n                    mon++;\n                    needAdvance = true;\n                }\n\n                if (needAdvance && (day != t || mon != tmon)) {\n                    cl.set(Calendar.SECOND, 0);\n                    cl.set(Calendar.MINUTE, 0);\n                    cl.set(Calendar.HOUR_OF_DAY, 0);\n                    cl.set(Calendar.DAY_OF_MONTH, day);\n                    cl.set(Calendar.MONTH, mon - 1);\n                    // '- 1' because calendar is 0-based for this field, and we\n                    // are 1-based\n                    continue;\n                }\n\n            } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule\n                if (lastDayOfWeek) { // are we looking for the last XXX day of\n                    // the month?\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    }\n                    if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n\n                    if (day + daysToAdd > lDay) { // did we already miss the\n                        // last one?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    }\n\n                    // find date of last occurrence of this day in this month...\n                    while ((day + daysToAdd + 7) <= lDay) {\n                        daysToAdd += 7;\n                    }\n\n                    day += daysToAdd;\n\n                    if (daysToAdd > 0) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' here because we are not promoting the month\n                        continue;\n                    }\n\n                } else if (nthDayOfWeek != 0) {\n                    // are we looking for the Nth XXX day in the month?\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    } else if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    boolean dayShifted = daysToAdd > 0;\n\n                    day += daysToAdd;\n                    int weekOfMonth = day / 7;\n                    if (day % 7 > 0) {\n                        weekOfMonth++;\n                    }\n\n                    daysToAdd = (nthDayOfWeek - weekOfMonth) * 7;\n                    day += daysToAdd;\n                    if (daysToAdd < 0\n                            || day > getLastDayOfMonth(mon, cl\n                                    .get(Calendar.YEAR))) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    } else if (daysToAdd > 0 || dayShifted) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' here because we are NOT promoting the month\n                        continue;\n                    }\n                } else {\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    st = daysOfWeek.tailSet(cDow);\n                    if (st != null && !st.isEmpty()) {\n                        dow = st.first();\n                    }\n\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    }\n                    if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n\n                    if (day + daysToAdd > lDay) { // will we pass the end of\n                        // the month?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    } else if (daysToAdd > 0) { // are we switching days?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' because calendar is 0-based for this field,\n                        // and we are 1-based\n                        continue;\n                    }\n                }\n            } else { // dayOfWSpec && !dayOfMSpec\n                throw new UnsupportedOperationException(\n                        \"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\");\n            }\n            cl.set(Calendar.DAY_OF_MONTH, day);\n\n            mon = cl.get(Calendar.MONTH) + 1;\n            // '+ 1' because calendar is 0-based for this field, and we are\n            // 1-based\n            int year = cl.get(Calendar.YEAR);\n            t = -1;\n\n            // test for expressions that never generate a valid fire date,\n            // but keep looping...\n            if (year > MAX_YEAR) {\n                return null;\n            }\n\n            // get month...................................................\n            st = months.tailSet(mon);\n            if (st != null && !st.isEmpty()) {\n                t = mon;\n                mon = st.first();\n            } else {\n                mon = months.first();\n                year++;\n            }\n            if (mon != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.HOUR_OF_DAY, 0);\n                cl.set(Calendar.DAY_OF_MONTH, 1);\n                cl.set(Calendar.MONTH, mon - 1);\n                // '- 1' because calendar is 0-based for this field, and we are\n                // 1-based\n                cl.set(Calendar.YEAR, year);\n                continue;\n            }\n            cl.set(Calendar.MONTH, mon - 1);\n            // '- 1' because calendar is 0-based for this field, and we are\n            // 1-based\n\n            year = cl.get(Calendar.YEAR);\n            t = -1;\n\n            // get year...................................................\n            st = years.tailSet(year);\n            if (st != null && !st.isEmpty()) {\n                t = year;\n                year = st.first();\n            } else {\n                return null; // ran out of years...\n            }\n\n            if (year != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.HOUR_OF_DAY, 0);\n                cl.set(Calendar.DAY_OF_MONTH, 1);\n                cl.set(Calendar.MONTH, 0);\n                // '- 1' because calendar is 0-based for this field, and we are\n                // 1-based\n                cl.set(Calendar.YEAR, year);\n                continue;\n            }\n            cl.set(Calendar.YEAR, year);\n\n            gotOne = true;\n        } // while( !done )\n\n        return cl.getTime();\n    }\n\n    /**\n     * Advance the calendar to the particular hour paying particular attention\n     * to daylight saving problems.\n     * \n     * @param cal the calendar to operate on\n     * @param hour the hour to set\n     */\n    protected void setCalendarHour(Calendar cal, int hour) {\n        cal.set(java.util.Calendar.HOUR_OF_DAY, hour);\n        if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) {\n            cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1);\n        }\n    }\n\n    /**\n     * Returns the time before the given time\n     * that the <code>CronExpression</code> matches.\n     *\n     * @param endTime a time for which the previous\n     *        matching time is returned\n     * @return the previous matching time before the given end time,\n     *         or null if there are no previous matching times\n     */ \n    public Date getTimeBefore(Date endTime) {\n        // the current implementation is not a direct calculation, but rather\n        // uses getTimeAfter with a binary search to find the previous match time\n        long end = endTime.getTime();\n        long min = 0; // the epoch date is the minimum supported by this class\n        long max = end;\n        // check if it's satisfiable at all\n        Date date = new Date(min);\n        Date after = getTimeAfter(date);\n        if (after == null || after.getTime() >= end)\n            return null; // there are no after-times before end\n        // from this point forward min's time-after is always less than end,\n        // and max's time-after is always equal to or greater than end\n        // so we just need to shrink the interval until they meet.\n        // optimization - perform inverse binary search to find a tighter lower bound\n        long interval = 60 * 60 * 1000; // start with a reasonable interval\n        while (interval < max) {\n            date.setTime(max - interval);\n            after = getTimeAfter(date);\n            if (after != null && after.getTime() < max) {\n                min = date.getTime(); // found a closer min\n                break;\n            }\n            interval *= 2;\n        }\n        // perform a regular binary search to find the earliest moment\n        // whose time-after is equal to or greater than the end time -\n        // this moment is the previous match time itself\n        while (max - min > 1000) { // we can stop at 1 second resolution\n            long mid = (min + max) >>> 1;\n            date.setTime(mid);\n            after = getTimeAfter(date);\n            if (after != null && after.getTime() < end)\n                min = mid;\n            else\n                max = mid;\n        }\n        date.setTime(max - max % 1000); // round to second\n        return date;\n    }\n\n    /**\n     * NOT YET IMPLEMENTED: Returns the final time that the \n     * <code>CronExpression</code> will match.\n     */\n    public Date getFinalFireTime() {\n        // FUTURE_TODO: implement QUARTZ-423\n        return null;\n    }\n    \n    protected boolean isLeapYear(int year) {\n        return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));\n    }\n\n    protected int getLastDayOfMonth(int monthNum, int year) {\n\n        switch (monthNum) {\n            case 1:\n                return 31;\n            case 2:\n                return (isLeapYear(year)) ? 29 : 28;\n            case 3:\n                return 31;\n            case 4:\n                return 30;\n            case 5:\n                return 31;\n            case 6:\n                return 30;\n            case 7:\n                return 31;\n            case 8:\n                return 31;\n            case 9:\n                return 30;\n            case 10:\n                return 31;\n            case 11:\n                return 30;\n            case 12:\n                return 31;\n            default:\n                throw new IllegalArgumentException(\"Illegal month number: \"\n                        + monthNum);\n        }\n    }\n    \n\n    private Optional<Integer> findSmallestDay(int day, int mon, int year, TreeSet<Integer> set) {\n        if (set.isEmpty()) {\n            return Optional.empty();\n        }\n\n        final int lastDay = getLastDayOfMonth(mon, year);\n        // For \"L\", \"L-1\", etc.\n        final int smallestDay = Optional.ofNullable(set.ceiling(LAST_DAY_OFFSET_END - (lastDay - day)))\n            .map(d -> d - LAST_DAY_OFFSET_START + 1)\n            .orElse(Integer.MAX_VALUE);\n\n        // For \"1\", \"2\", etc.\n        SortedSet<Integer> st = set.subSet(day, LAST_DAY_OFFSET_START);\n        // make sure we don't over-run a short month, such as february\n        if (!st.isEmpty() && st.first() < smallestDay && st.first() <= lastDay) {\n           return Optional.of(st.first());\n        }\n\n        if (smallestDay == Integer.MAX_VALUE) {\n            return Optional.empty();\n        } else {\n            return Optional.of(smallestDay + lastDay - LAST_DAY_OFFSET_START + 1);\n        }\n    }\n\n    private void readObject(java.io.ObjectInputStream stream)\n        throws java.io.IOException, ClassNotFoundException {\n        \n        stream.defaultReadObject();\n        try {\n            buildExpression(cronExpression);\n        } catch (Exception ignore) {\n        } // never happens\n    }    \n    \n    @Override\n    @Deprecated\n    public Object clone() {\n        return new CronExpression(this);\n    }\n}\n\nclass ValueSet {\n    public int value;\n\n    public int pos;\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/CronScheduleBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.text.ParseException;\nimport java.util.TimeZone;\n\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\n\n/**\n * <code>CronScheduleBuilder</code> is a {@link ScheduleBuilder} that defines\n * {@link CronExpression}-based schedules for <code>Trigger</code>s.\n * \n * <p>\n * Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL). The DSL can best be utilized\n * through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>,\n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> and\n * the various <code>ScheduleBuilder</code> implementations.\n * </p>\n * \n * <p>\n * Client code can then use the DSL to write code such as this:\n * </p>\n * \n * <pre>\n * JobDetail job = newJob(MyJob.class).withIdentity(&quot;myJob&quot;).build();\n * \n * Trigger trigger = newTrigger()\n *         .withIdentity(triggerKey(&quot;myTrigger&quot;, &quot;myTriggerGroup&quot;))\n *         .withSchedule(dailyAtHourAndMinute(10, 0))\n *         .startAt(futureDate(10, MINUTES)).build();\n * \n * scheduler.scheduleJob(job, trigger);\n * \n * </pre>\n * \n * @see CronExpression\n * @see CronTrigger\n * @see ScheduleBuilder\n * @see SimpleScheduleBuilder \n * @see CalendarIntervalScheduleBuilder\n * @see TriggerBuilder\n */\npublic class CronScheduleBuilder extends ScheduleBuilder<CronTrigger> {\n\n    private final CronExpression cronExpression;\n    private int misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_SMART_POLICY;\n\n    protected CronScheduleBuilder(CronExpression cronExpression) {\n        if (cronExpression == null) {\n            throw new NullPointerException(\"cronExpression cannot be null\");\n        }\n        this.cronExpression = cronExpression;\n    }\n\n    /**\n     * Build the actual Trigger -- NOT intended to be invoked by end users, but\n     * will rather be invoked by a TriggerBuilder which this ScheduleBuilder is\n     * given to.\n     * \n     * @see TriggerBuilder#withSchedule(ScheduleBuilder)\n     */\n    @Override\n    public MutableTrigger build() {\n\n        CronTriggerImpl ct = new CronTriggerImpl();\n\n        ct.setCronExpression(cronExpression);\n        ct.setTimeZone(cronExpression.getTimeZone());\n        ct.setMisfireInstruction(misfireInstruction);\n\n        return ct;\n    }\n\n    /**\n     * Create a CronScheduleBuilder with the given cron-expression string -\n     * which is presumed to be a valid cron expression (and hence only a\n     * RuntimeException will be thrown if it is not).\n     * \n     * @param cronExpression\n     *            the cron expression string to base the schedule on.\n     * @return the new CronScheduleBuilder\n     * @throws RuntimeException\n     *             wrapping a ParseException if the expression is invalid\n     * @see CronExpression\n     */\n    public static CronScheduleBuilder cronSchedule(String cronExpression) {\n        try {\n            return cronSchedule(new CronExpression(cronExpression));\n        } catch (ParseException e) {\n            // all methods of construction ensure the expression is valid by\n            // this point...\n            throw new RuntimeException(\"CronExpression '\" + cronExpression\n                    + \"' is invalid.\", e);\n        }\n    }\n\n    /**\n     * Create a CronScheduleBuilder with the given cron-expression string -\n     * which may not be a valid cron expression (and hence a ParseException will\n     * be thrown if it is not).\n     * \n     * @param cronExpression\n     *            the cron expression string to base the schedule on.\n     * @return the new CronScheduleBuilder\n     * @throws ParseException\n     *             if the expression is invalid\n     * @see CronExpression\n     */\n    public static CronScheduleBuilder cronScheduleNonvalidatedExpression(\n            String cronExpression) throws ParseException {\n        return cronSchedule(new CronExpression(cronExpression));\n    }\n\n    private static CronScheduleBuilder cronScheduleNoParseException(\n            String presumedValidCronExpression) {\n        try {\n            return cronSchedule(new CronExpression(presumedValidCronExpression));\n        } catch (ParseException e) {\n            // all methods of construction ensure the expression is valid by\n            // this point...\n            throw new RuntimeException(\n                    \"CronExpression '\"\n                            + presumedValidCronExpression\n                            + \"' is invalid, which should not be possible, please report bug to Quartz developers.\",\n                    e);\n        }\n    }\n\n    /**\n     * Create a CronScheduleBuilder with the given cron-expression.\n     * \n     * @param cronExpression\n     *            the cron expression to base the schedule on.\n     * @return the new CronScheduleBuilder\n     * @see CronExpression\n     */\n    public static CronScheduleBuilder cronSchedule(CronExpression cronExpression) {\n        return new CronScheduleBuilder(cronExpression);\n    }\n\n    /**\n     * Create a CronScheduleBuilder with a cron-expression that sets the\n     * schedule to fire every day at the given time (hour and minute).\n     * \n     * @param hour\n     *            the hour of day to fire\n     * @param minute\n     *            the minute of the given hour to fire\n     * @return the new CronScheduleBuilder\n     * @see CronExpression\n     */\n    public static CronScheduleBuilder dailyAtHourAndMinute(int hour, int minute) {\n        DateBuilder.validateHour(hour);\n        DateBuilder.validateMinute(minute);\n\n        String cronExpression = String.format(\"0 %d %d ? * *\", minute, hour);\n\n        return cronScheduleNoParseException(cronExpression);\n    }\n\n    /**\n     * Create a CronScheduleBuilder with a cron-expression that sets the\n     * schedule to fire at the given day at the given time (hour and minute) on\n     * the given days of the week.\n     * \n     * @param daysOfWeek\n     *            the day of the week to fire\n     * @param hour\n     *            the hour of day to fire\n     * @param minute\n     *            the minute of the given hour to fire\n     * @return the new CronScheduleBuilder\n     * @see CronExpression\n     * @see DateBuilder#MONDAY\n     * @see DateBuilder#TUESDAY\n     * @see DateBuilder#WEDNESDAY\n     * @see DateBuilder#THURSDAY\n     * @see DateBuilder#FRIDAY\n     * @see DateBuilder#SATURDAY\n     * @see DateBuilder#SUNDAY\n     */\n\n    public static CronScheduleBuilder atHourAndMinuteOnGivenDaysOfWeek(\n            int hour, int minute, Integer... daysOfWeek) {\n        if (daysOfWeek == null || daysOfWeek.length == 0)\n            throw new IllegalArgumentException(\n                    \"You must specify at least one day of week.\");\n        for (int dayOfWeek : daysOfWeek)\n            DateBuilder.validateDayOfWeek(dayOfWeek);\n        DateBuilder.validateHour(hour);\n        DateBuilder.validateMinute(minute);\n\n        StringBuilder cronExpression = new StringBuilder(String.format(\"0 %d %d ? * %d\", minute, hour,\n                daysOfWeek[0]));\n\n        for (int i = 1; i < daysOfWeek.length; i++)\n            cronExpression.append(\",\").append(daysOfWeek[i]);\n\n        return cronScheduleNoParseException(cronExpression.toString());\n    }\n\n    /**\n     * Create a CronScheduleBuilder with a cron-expression that sets the\n     * schedule to fire one per week on the given day at the given time (hour\n     * and minute).\n     * \n     * @param dayOfWeek\n     *            the day of the week to fire\n     * @param hour\n     *            the hour of day to fire\n     * @param minute\n     *            the minute of the given hour to fire\n     * @return the new CronScheduleBuilder\n     * @see CronExpression\n     * @see DateBuilder#MONDAY\n     * @see DateBuilder#TUESDAY\n     * @see DateBuilder#WEDNESDAY\n     * @see DateBuilder#THURSDAY\n     * @see DateBuilder#FRIDAY\n     * @see DateBuilder#SATURDAY\n     * @see DateBuilder#SUNDAY\n     */\n    public static CronScheduleBuilder weeklyOnDayAndHourAndMinute(\n            int dayOfWeek, int hour, int minute) {\n        DateBuilder.validateDayOfWeek(dayOfWeek);\n        DateBuilder.validateHour(hour);\n        DateBuilder.validateMinute(minute);\n\n        String cronExpression = String.format(\"0 %d %d ? * %d\", minute, hour,\n                dayOfWeek);\n\n        return cronScheduleNoParseException(cronExpression);\n    }\n\n    /**\n     * Create a CronScheduleBuilder with a cron-expression that sets the\n     * schedule to fire one per month on the given day of month at the given\n     * time (hour and minute).\n     * \n     * @param dayOfMonth\n     *            the day of the month to fire\n     * @param hour\n     *            the hour of day to fire\n     * @param minute\n     *            the minute of the given hour to fire\n     * @return the new CronScheduleBuilder\n     * @see CronExpression\n     */\n    public static CronScheduleBuilder monthlyOnDayAndHourAndMinute(\n            int dayOfMonth, int hour, int minute) {\n        DateBuilder.validateDayOfMonth(dayOfMonth);\n        DateBuilder.validateHour(hour);\n        DateBuilder.validateMinute(minute);\n\n        String cronExpression = String.format(\"0 %d %d %d * ?\", minute, hour,\n                dayOfMonth);\n\n        return cronScheduleNoParseException(cronExpression);\n    }\n\n    /**\n     * The <code>TimeZone</code> in which to base the schedule.\n     * \n     * @param timezone\n     *            the time-zone for the schedule.\n     * @return the updated CronScheduleBuilder\n     * @see CronExpression#getTimeZone()\n     */\n    public CronScheduleBuilder inTimeZone(TimeZone timezone) {\n        cronExpression.setTimeZone(timezone);\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the\n     * {@link Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY} instruction.\n     * \n     * @return the updated CronScheduleBuilder\n     * @see Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY\n     */\n    public CronScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {\n        misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the\n     * {@link CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING} instruction.\n     * \n     * @return the updated CronScheduleBuilder\n     * @see CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING\n     */\n    public CronScheduleBuilder withMisfireHandlingInstructionDoNothing() {\n        misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the\n     * {@link CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW} instruction.\n     * \n     * @return the updated CronScheduleBuilder\n     * @see CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\n     */\n    public CronScheduleBuilder withMisfireHandlingInstructionFireAndProceed() {\n        misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        return this;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/CronTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.TimeZone;\n\n/**\n * The public interface for inspecting settings specific to a CronTrigger, .\n * which is used to fire a <code>{@link org.quartz.Job}</code>\n * at given moments in time, defined with Unix 'cron-like' schedule definitions.\n * \n * <p>\n * For those unfamiliar with \"cron\", this means being able to create a firing\n * schedule such as: \"At 8:00am every Monday through Friday\" or \"At 1:30am\n * every last Friday of the month\".\n * </p>\n * \n * <p>\n * The format of a \"Cron-Expression\" string is documented on the \n * {@link org.quartz.CronExpression} class.\n * </p>\n * \n * <p>\n * Here are some full examples: </p>\n * <table>\n * <caption>Examples of cron expressions and their meanings.</caption>\n * <tr>\n * <th>Expression</th>\n * <th>&nbsp;</th>\n * <th>Meaning</th>\n * </tr>\n * <tr>\n * <td><code>\"0 0 12 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 12pm (noon) every day</code></td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * *\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am every day</code></td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am every day</code></td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 * * ? *\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am every day</code></td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 * * ? 2005\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am every day during the year 2005</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 * 14 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire every minute starting at 2pm and ending at 2:59pm, every day</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 0/5 14 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 0/5 14,18 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 0-5 14 * * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire every minute starting at 2pm and ending at 2:05pm, every day</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 10,44 14 ? 3 WED\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * MON-FRI\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 15 * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on the 15th day of every month</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 L * ?\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on the last day of every month</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * 6L\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on the last Friday of every month</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * 6L\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on the last Friday of every month</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * 6L 2002-2005\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on every last Friday of every month during the years 2002, 2003, 2004 and 2005</code>\n * </td>\n * </tr>\n * <tr>\n * <td><code>\"0 15 10 ? * 6#3\"</code></td>\n * <td>&nbsp;</td>\n * <td><code>Fire at 10:15am on the third Friday of every month</code>\n * </td>\n * </tr>\n * </table>\n * \n * <p>\n * Pay attention to the effects of '?' and '*' in the day-of-week and\n * day-of-month fields!\n * </p>\n * \n * <p>\n * <b>NOTES:</b>\n * </p>\n * <ul>\n * <li>Support for specifying both a day-of-week and a day-of-month value is\n * not complete (you'll need to use the '?' character in on of these fields).\n * </li>\n * <li>Be careful when setting fire times between mid-night and 1:00 AM -\n * \"daylight savings\" can cause a skip or a repeat depending on whether the\n * time moves back or jumps forward.</li>\n * </ul>\n * \n * @see CronScheduleBuilder\n * @see TriggerBuilder\n * \n * @author jhouse\n * @author Contributions from Mads Henderson\n */\npublic interface CronTrigger extends Trigger {\n\n    long serialVersionUID = -8644953146451592766L;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link CronTrigger}</code> wants to be fired now\n     * by <code>Scheduler</code>.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link CronTrigger}</code> wants to have it's\n     * next-fire-time updated to the next time in the schedule after the\n     * current time (taking into account any associated <code>{@link Calendar}</code>,\n     * but it does not want to be fired now.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_DO_NOTHING = 2;\n\n    String getCronExpression();\n\n    /**\n     * <p>\n     * Returns the time zone for which the <code>cronExpression</code> of\n     * this <code>CronTrigger</code> will be resolved.\n     * </p>\n     */\n    TimeZone getTimeZone();\n\n    String getExpressionSummary();\n\n    TriggerBuilder<CronTrigger> getTriggerBuilder();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/DailyTimeIntervalScheduleBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.triggers.DailyTimeIntervalTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\n\n/**\n * A {@link ScheduleBuilder} implementation that build schedule for DailyTimeIntervalTrigger.\n * \n * <p>This builder provide an extra convenient method for you to set the trigger's endTimeOfDay. You may\n * use either endingDailyAt() or endingDailyAfterCount() to set the value. The later will auto calculate\n * your endTimeOfDay by using the interval, intervalUnit and startTimeOfDay to perform the calculation.\n *  \n * <p>When using endingDailyAfterCount(), you should note that it is used to calculating endTimeOfDay. So\n * if your startTime on the first day is already pass by a time that would not add up to the count you\n * expected, until the next day comes. Remember that DailyTimeIntervalTrigger will use startTimeOfDay\n * and endTimeOfDay as fresh per each day!\n *  \n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(onDaysOfTheWeek(MONDAY, THURSDAY))\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *   \n * @since 2.1.0\n * \n * @author James House\n * @author Zemian Deng &lt;saltnlight5@gmail.com&gt;\n */\npublic class DailyTimeIntervalScheduleBuilder extends ScheduleBuilder<DailyTimeIntervalTrigger> {\n\n    private int interval = 1;\n    private IntervalUnit intervalUnit = IntervalUnit.MINUTE;\n    private Set<Integer> daysOfWeek;\n    private TimeOfDay startTimeOfDay;\n    private TimeOfDay endTimeOfDay;\n    private int repeatCount = DailyTimeIntervalTrigger.REPEAT_INDEFINITELY;\n\n    private int misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_SMART_POLICY;\n    \n    /**\n     * A set of all days of the week.\n     * \n     * The set contains all values between {@link java.util.Calendar#SUNDAY} and {@link java.util.Calendar#SATURDAY} \n     * (the integers from 1 through 7). \n     */\n    public static final Set<Integer> ALL_DAYS_OF_THE_WEEK;\n    \n    /** \n     * A set of the business days of the week (for locales similar to the USA).\n     * \n     * The set contains all values between {@link java.util.Calendar#MONDAY} and {@link java.util.Calendar#FRIDAY} \n     * (the integers from 2 through 6). \n     */\n    public static final Set<Integer> MONDAY_THROUGH_FRIDAY;\n    \n    /**\n     * A set of the weekend days of the week (for locales similar to the USA).\n     * \n     * The set contains {@link java.util.Calendar#SATURDAY} and {@link java.util.Calendar#SUNDAY} \n     */\n    public static final Set<Integer> SATURDAY_AND_SUNDAY;\n    \n    static {\n        Set<Integer> t = new HashSet<>(7);\n        for(int i=Calendar.SUNDAY; i <= Calendar.SATURDAY; i++)\n            t.add(i);\n        ALL_DAYS_OF_THE_WEEK = Collections.unmodifiableSet(t);\n        \n        t = new HashSet<>(5);\n        for(int i=Calendar.MONDAY; i <= Calendar.FRIDAY; i++)\n            t.add(i);\n        MONDAY_THROUGH_FRIDAY = Collections.unmodifiableSet(t);\n        \n        t = new HashSet<>(2);\n        t.add(Calendar.SUNDAY);\n        t.add(Calendar.SATURDAY);\n        SATURDAY_AND_SUNDAY = Collections.unmodifiableSet(t);\n    }\n    \n    protected DailyTimeIntervalScheduleBuilder() {\n    }\n    \n    /**\n     * Create a DailyTimeIntervalScheduleBuilder.\n     * \n     * @return the new DailyTimeIntervalScheduleBuilder\n     */\n    public static DailyTimeIntervalScheduleBuilder dailyTimeIntervalSchedule() {\n        return new DailyTimeIntervalScheduleBuilder();\n    }\n    \n    /**\n     * Build the actual Trigger -- NOT intended to be invoked by end users,\n     * but will rather be invoked by a TriggerBuilder which this \n     * ScheduleBuilder is given to.\n     * \n     * @see TriggerBuilder#withSchedule(ScheduleBuilder)\n     */\n    @Override\n    public MutableTrigger build() {\n\n        DailyTimeIntervalTriggerImpl st = new DailyTimeIntervalTriggerImpl();\n        st.setRepeatInterval(interval);\n        st.setRepeatIntervalUnit(intervalUnit);\n        st.setMisfireInstruction(misfireInstruction);\n        st.setRepeatCount(repeatCount);\n        \n        if(daysOfWeek != null)\n            st.setDaysOfWeek(daysOfWeek);\n        else\n            st.setDaysOfWeek(ALL_DAYS_OF_THE_WEEK);\n\n        if(startTimeOfDay != null)\n            st.setStartTimeOfDay(startTimeOfDay);\n        else\n            st.setStartTimeOfDay(TimeOfDay.hourAndMinuteOfDay(0, 0));\n\n        if(endTimeOfDay != null)\n            st.setEndTimeOfDay(endTimeOfDay);\n        else\n            st.setEndTimeOfDay(TimeOfDay.hourMinuteAndSecondOfDay(23, 59, 59));\n        \n        return st;\n    }\n\n    /**\n     * Specify the time unit and interval for the Trigger to be produced.\n     * \n     * @param timeInterval the interval at which the trigger should repeat.\n     * @param unit the time unit (IntervalUnit) of the interval. The only intervals that are valid for this type of \n     * trigger are {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#getRepeatInterval()\n     * @see DailyTimeIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public DailyTimeIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit) {\n        if (unit == null || !(unit.equals(IntervalUnit.SECOND) || \n                unit.equals(IntervalUnit.MINUTE) ||unit.equals(IntervalUnit.HOUR)))\n            throw new IllegalArgumentException(\"Invalid repeat IntervalUnit (must be SECOND, MINUTE or HOUR).\");\n        validateInterval(timeInterval);\n        this.interval = timeInterval;\n        this.intervalUnit = unit;\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.SECOND that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInSeconds the number of seconds at which the trigger should repeat.\n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#getRepeatInterval()\n     * @see DailyTimeIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public DailyTimeIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds) {\n        withInterval(intervalInSeconds, IntervalUnit.SECOND);\n        return this;\n    }\n    \n    /**\n     * Specify an interval in the IntervalUnit.MINUTE that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInMinutes the number of minutes at which the trigger should repeat.\n     * @return the updated CalendarIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#getRepeatInterval()\n     * @see DailyTimeIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public DailyTimeIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes) {\n        withInterval(intervalInMinutes, IntervalUnit.MINUTE);\n        return this;\n    }\n\n    /**\n     * Specify an interval in the IntervalUnit.HOUR that the produced \n     * Trigger will repeat at.\n     * \n     * @param intervalInHours the number of hours at which the trigger should repeat.\n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#getRepeatInterval()\n     * @see DailyTimeIntervalTrigger#getRepeatIntervalUnit()\n     */\n    public DailyTimeIntervalScheduleBuilder withIntervalInHours(int intervalInHours) {\n        withInterval(intervalInHours, IntervalUnit.HOUR);\n        return this;\n    }\n\n    /**\n     * Set the trigger to fire on the given days of the week.\n     * \n     * @param onDaysOfWeek a Set containing the integers representing the days of the week, per the values 1-7 as defined by \n     * {@link java.util.Calendar#SUNDAY} - {@link java.util.Calendar#SATURDAY}. \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder onDaysOfTheWeek(Set<Integer> onDaysOfWeek) {\n        if(onDaysOfWeek == null || onDaysOfWeek.isEmpty())\n            throw new IllegalArgumentException(\"Days of week must be an non-empty set.\");\n        for (Integer day : onDaysOfWeek)\n            if (!ALL_DAYS_OF_THE_WEEK.contains(day))\n                throw new IllegalArgumentException(\"Invalid value for day of week: \" + day);\n                \n        this.daysOfWeek = onDaysOfWeek;\n        return this;\n    }\n\n    /**\n     * Set the trigger to fire on the given days of the week.\n     * \n     * @param onDaysOfWeek a variable length list of Integers representing the days of the week, per the values 1-7 as \n     * defined by {@link java.util.Calendar#SUNDAY} - {@link java.util.Calendar#SATURDAY}. \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder onDaysOfTheWeek(Integer ... onDaysOfWeek) {\n        Set<Integer> daysAsSet = new HashSet<>(12);\n        Collections.addAll(daysAsSet, onDaysOfWeek);\n        return onDaysOfTheWeek(daysAsSet);\n    }\n    \n    /**\n     * Set the trigger to fire on the days from Monday through Friday.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder onMondayThroughFriday() {\n        this.daysOfWeek = MONDAY_THROUGH_FRIDAY;\n        return this;\n    }\n\n    /**\n     * Set the trigger to fire on the days Saturday and Sunday.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder onSaturdayAndSunday() {\n        this.daysOfWeek = SATURDAY_AND_SUNDAY;\n        return this;\n    }\n\n    /**\n     * Set the trigger to fire on all days of the week.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder onEveryDay() {\n        this.daysOfWeek = ALL_DAYS_OF_THE_WEEK;\n        return this;\n    }\n\n    /**\n     * Set the trigger to begin firing each day at the given time.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder startingDailyAt(TimeOfDay timeOfDay) {\n        if(timeOfDay == null)\n            throw new IllegalArgumentException(\"Start time of day cannot be null!\");\n        \n        this.startTimeOfDay = timeOfDay;\n        return this;\n    }\n\n    /**\n     * Set the startTimeOfDay for this trigger to end firing each day at the given time.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder endingDailyAt(TimeOfDay timeOfDay) {        \n        this.endTimeOfDay = timeOfDay;\n        return this;\n    }\n\n    /**\n     * Calculate and set the endTimeOfDay using count, interval and starTimeOfDay. This means\n     * that these must be set before this method is call.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder endingDailyAfterCount(int count) {\n        if(count <=0)\n            throw new IllegalArgumentException(\"Ending daily after count must be a positive number!\");\n        \n        if(startTimeOfDay == null)\n            throw new IllegalArgumentException(\"You must set the startDailyAt() before calling this endingDailyAfterCount()!\");\n        \n        Date today = new Date();\n        Date startTimeOfDayDate = startTimeOfDay.getTimeOfDayForDate(today);\n        Date maxEndTimeOfDayDate = TimeOfDay.hourMinuteAndSecondOfDay(23, 59, 59).getTimeOfDayForDate(today);\n        long remainingMillisInDay = maxEndTimeOfDayDate.getTime() - startTimeOfDayDate.getTime();\n        long intervalInMillis;\n        if (intervalUnit == IntervalUnit.SECOND)\n            intervalInMillis = interval * 1000L;\n        else if (intervalUnit == IntervalUnit.MINUTE)\n                intervalInMillis = interval * 1000L * 60;\n        else if (intervalUnit == IntervalUnit.HOUR)\n            intervalInMillis = interval * 1000L * 60 * 60;\n        else\n            throw new IllegalArgumentException(\"The IntervalUnit: \" + intervalUnit + \" is invalid for this trigger.\"); \n        \n        if (remainingMillisInDay - intervalInMillis <= 0)\n            throw new IllegalArgumentException(\"The startTimeOfDay is too late with given Interval and IntervalUnit values.\");\n        \n        long maxNumOfCount = (remainingMillisInDay / intervalInMillis);\n        if (count > maxNumOfCount)\n            throw new IllegalArgumentException(\"The given count \" + count + \" is too large! The max you can set is \" + maxNumOfCount);\n        \n        long incrementInMillis = (count - 1) * intervalInMillis;\n        Date endTimeOfDayDate = new Date(startTimeOfDayDate.getTime() + incrementInMillis);\n        \n        if (endTimeOfDayDate.getTime() > maxEndTimeOfDayDate.getTime())\n            throw new IllegalArgumentException(\"The given count \" + count + \" is too large! The max you can set is \" + maxNumOfCount);\n        \n        Calendar cal = Calendar.getInstance();\n        cal.setTime(endTimeOfDayDate);\n        int hour = cal.get(Calendar.HOUR_OF_DAY);\n        int minute = cal.get(Calendar.MINUTE);\n        int second = cal.get(Calendar.SECOND);\n        \n        endTimeOfDay = TimeOfDay.hourMinuteAndSecondOfDay(hour, minute, second);\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY} instruction.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY\n     */\n    public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {\n        misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;\n        return this;\n    }\n    \n    /**\n     * If the Trigger misfires, use the \n     * {@link DailyTimeIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING} instruction.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#MISFIRE_INSTRUCTION_DO_NOTHING\n     */\n    public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing() {\n        misfireInstruction = DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link DailyTimeIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW} instruction.\n     * \n     * @return the updated DailyTimeIntervalScheduleBuilder\n     * @see DailyTimeIntervalTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\n     */\n    public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed() {\n        misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        return this;\n    }\n    \n    /**\n     * Set number of times for interval to repeat.\n     * \n     * <p>Note: if you want total count = 1 (at start time) + repeatCount</p>\n     * \n     * @return the new DailyTimeIntervalScheduleBuilder\n     */\n    public DailyTimeIntervalScheduleBuilder withRepeatCount(int repeatCount) {\n        this.repeatCount = repeatCount;\n        return this;\n    }\n\n    private void validateInterval(int timeInterval) {\n        if(timeInterval <= 0)\n            throw new IllegalArgumentException(\"Interval must be a positive value.\");\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/DailyTimeIntervalTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.Set;\n\nimport org.quartz.DateBuilder.IntervalUnit;\n\n/**\n * A <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * based upon daily repeating time intervals.\n * \n * <p>The trigger will fire every N (see {@link #getRepeatInterval()} ) seconds, minutes or hours\n * (see {@link #getRepeatIntervalUnit()}) during a given time window on specified days of the week.</p>\n * \n * <p>For example#1, a trigger can be set to fire every 72 minutes between 8:00 and 11:00 everyday. It's fire times would \n * be 8:00, 9:12, 10:24, then next day would repeat: 8:00, 9:12, 10:24 again.</p>\n * \n * <p>For example#2, a trigger can be set to fire every 23 minutes between 9:20 and 16:47 Monday through Friday.</p>\n * \n * <p>On each day, the starting fire time is reset to startTimeOfDay value, and then it will add repeatInterval value to it until\n * the endTimeOfDay is reached. If you set daysOfWeek values, then fire time will only occur during those week days period.</p> \n * \n * <p>The default values for fields if not set are: startTimeOfDay defaults to 00:00:00, the endTimeOfDay default to 23:59:59, \n * and daysOfWeek is default to every day. The startTime default to current time-stamp now, while endTime has not value.</p>\n * \n * <p>If startTime is before startTimeOfDay, then it has no affect. Else if startTime after startTimeOfDay, then the first fire time \n * for that day will be normal startTimeOfDay incremental values after startTime value. Same reversal logic is applied to endTime \n * with endTimeOfDay.</p>\n *   \n * @see DailyTimeIntervalScheduleBuilder\n * \n * @since 2.1.0\n * \n * @author James House\n * @author Zemian Deng &lt;saltnlight5@gmail.com&gt;\n */\npublic interface DailyTimeIntervalTrigger extends Trigger {\n\n    /**\n     * <p>\n     * Used to indicate the 'repeat count' of the trigger is indefinite. Or in\n     * other words, the trigger should repeat continually until the trigger's\n     * ending timestamp.\n     * </p>\n     */\n    int REPEAT_INDEFINITELY = -1;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link DailyTimeIntervalTrigger}</code> wants to be\n     * fired now by <code>Scheduler</code>.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link DailyTimeIntervalTrigger}</code> wants to have it's\n     * next-fire-time updated to the next time in the schedule after the\n     * current time (taking into account any associated <code>{@link Calendar}</code>,\n     * but it does not want to be fired now.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_DO_NOTHING = 2;\n\n    /**\n     * <p>Get the interval unit - the time unit on with the interval applies.</p>\n     * \n     * <p>The only intervals that are valid for this type of trigger are {@link IntervalUnit#SECOND},\n     * {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.</p>\n     */\n    IntervalUnit getRepeatIntervalUnit();\n    \n    /**\n     * <p>\n     * Get the number of times for interval this trigger should\n     * repeat, after which it will be automatically deleted.\n     * </p>\n     * \n     * @see #REPEAT_INDEFINITELY\n     */\n    int getRepeatCount();\n\n    /**\n     * <p>\n     * Get the time interval that will be added to the <code>DateIntervalTrigger</code>'s\n     * fire time (in the set repeat interval unit) in order to calculate the time of the \n     * next trigger repeat.\n     * </p>\n     */\n    int getRepeatInterval();\n    \n    /**\n     * The time of day to start firing at the given interval.\n     */\n    TimeOfDay getStartTimeOfDay();\n    \n    /**\n     * The time of day to complete firing at the given interval.\n     */\n    TimeOfDay getEndTimeOfDay();\n\n    /**\n     * The days of the week upon which to fire.\n     * \n     * @return a Set containing the integers representing the days of the week, per the values 1-7 as defined by \n     * {@link java.util.Calendar#SUNDAY} - {@link java.util.Calendar#SATURDAY}. \n     */\n    Set<Integer> getDaysOfWeek();\n    \n    /**\n     * <p>\n     * Get the number of times the <code>DateIntervalTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    int getTimesTriggered();\n\n    TriggerBuilder<DailyTimeIntervalTrigger> getTriggerBuilder();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/DateBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz;\n\nimport java.time.Clock;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.Year;\nimport java.time.ZoneId;\nimport java.time.ZoneOffset;\nimport java.time.ZonedDateTime;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * <code>DateBuilder</code> is used to conveniently create\n * <code>java.util.Date</code> instances that meet particular criteria.\n *\n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>,\n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code>\n * and the various <code>ScheduleBuilder</code> implementations.</p>\n *\n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *\n *         Trigger trigger = newTrigger()\n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *\n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *\n * @see TriggerBuilder\n * @see JobBuilder\n */\npublic class DateBuilder {\n\n    public enum IntervalUnit { MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR }\n\n    public static final int SUNDAY = 1;\n\n    public static final int MONDAY = 2;\n\n    public static final int TUESDAY = 3;\n\n    public static final int WEDNESDAY = 4;\n\n    public static final int THURSDAY = 5;\n\n    public static final int FRIDAY = 6;\n\n    public static final int SATURDAY = 7;\n\n    public static final int JANUARY = 1;\n\n    public static final int FEBRUARY = 2;\n\n    public static final int MARCH = 3;\n\n    public static final int APRIL = 4;\n\n    public static final int MAY = 5;\n\n    public static final int JUNE = 6;\n\n    public static final int JULY = 7;\n\n    public static final int AUGUST = 8;\n\n    public static final int SEPTEMBER = 9;\n\n    public static final int OCTOBER = 10;\n\n    public static final int NOVEMBER = 11;\n\n    public static final int DECEMBER = 12;\n\n    public static final long MILLISECONDS_IN_MINUTE = 60L * 1000L;\n\n    public static final long MILLISECONDS_IN_HOUR = 60L * 60L * 1000L;\n\n    public static final long SECONDS_IN_MOST_DAYS = 24L * 60L * 60L;\n\n    public static final long MILLISECONDS_IN_DAY = SECONDS_IN_MOST_DAYS * 1000L;\n\n    private int month = -1;\n    private int day = -1;\n    private int year = -1;\n    private int hour = -1;\n    private int minute = -1;\n    private int second = -1;\n    private ZoneId zoneId;\n    private Locale lc;\n    private Clock clock = Clock.systemDefaultZone();\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the system default timezone.\n     */\n    private DateBuilder() {\n        this(TimeZone.getDefault());\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given timezone.\n     */\n    private DateBuilder(TimeZone tz) {\n        this.zoneId = tz.toZoneId();\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given locale.\n     */\n    private DateBuilder(Locale lc) {\n        this(Calendar.getInstance(lc).getTimeZone());\n        this.lc = lc;\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given timezone and locale.\n     */\n    private DateBuilder(TimeZone tz, Locale lc) {\n        this(Calendar.getInstance(tz, lc).getTimeZone());\n\n        this.zoneId = tz.toZoneId();\n        this.lc = lc;\n    }\n\n    void setClock(Clock clock) {\n        this.clock = clock;\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the system default timezone.\n     */\n    public static DateBuilder newDate() {\n        return new DateBuilder();\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given timezone.\n     */\n    public static DateBuilder newDateInTimezone(TimeZone tz) {\n        return new DateBuilder(tz);\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given locale.\n     */\n    public static DateBuilder newDateInLocale(Locale lc) {\n        return new DateBuilder(lc);\n    }\n\n    /**\n     * Create a DateBuilder, with initial settings for the current date and time in the given timezone and locale.\n     */\n    public static DateBuilder newDateInTimeZoneAndLocale(TimeZone tz, Locale lc) {\n        return new DateBuilder(tz, lc);\n    }\n\n    /**\n     * Build the Date defined by this builder instance.\n     */\n    public Date build() {\n        var useZoneId = (zoneId != null) ? zoneId : ZoneId.systemDefault();\n        if (lc != null && useZoneId == null) {\n            useZoneId = Calendar.getInstance(lc).getTimeZone().toZoneId();\n        }\n\n        if (year == -1 || month == -1 || day == -1 || hour == -1 || minute == -1 || second == -1) {\n            var zdt = ZonedDateTime.now(clock).withZoneSameInstant(useZoneId);\n\n            year = zdt.getYear();\n            month = zdt.getMonthValue();\n            day = zdt.getDayOfMonth();\n            hour = zdt.getHour();\n            minute = zdt.getMinute();\n            second = zdt.getSecond();\n        }\n        var zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, useZoneId);\n\n        return Date.from(zdt.toInstant());\n    }\n\n    /**\n     * Set the hour (0-23) for the Date that will be built by this builder.\n     */\n    public DateBuilder atHourOfDay(int atHour) {\n        validateHour(atHour);\n\n        this.hour = atHour;\n        return this;\n    }\n\n    /**\n     * Set the minute (0-59) for the Date that will be built by this builder.\n     */\n    public DateBuilder atMinute(int atMinute) {\n        validateMinute(atMinute);\n\n        this.minute = atMinute;\n        return this;\n    }\n\n    /**\n     * Set the second (0-59) for the Date that will be built by this builder, and truncate the milliseconds to 000.\n     */\n    public DateBuilder atSecond(int atSecond) {\n        validateSecond(atSecond);\n\n        this.second = atSecond;\n        return this;\n    }\n\n    public DateBuilder atHourMinuteAndSecond(int atHour, int atMinute, int atSecond) {\n        validateHour(atHour);\n        validateMinute(atMinute);\n        validateSecond(atSecond);\n\n        this.hour = atHour;\n        this.second = atSecond;\n        this.minute = atMinute;\n        return this;\n    }\n\n    /**\n     * Set the day of month (1-31) for the Date that will be built by this builder.\n     */\n    public DateBuilder onDay(int onDay) {\n        validateDayOfMonth(onDay);\n\n        this.day = onDay;\n        return this;\n    }\n\n    /**\n     * Set the month (1-12) for the Date that will be built by this builder.\n     */\n    public DateBuilder inMonth(int inMonth) {\n        validateMonth(inMonth);\n\n        this.month = inMonth;\n        return this;\n    }\n\n    public DateBuilder inMonthOnDay(int inMonth, int onDay) {\n        validateMonth(inMonth);\n        validateDayOfMonth(onDay);\n\n        this.month = inMonth;\n        this.day = onDay;\n        return this;\n    }\n\n    /**\n     * Set the year for the Date that will be built by this builder.\n     */\n    public DateBuilder inYear(int inYear) {\n        validateYear(inYear);\n\n        this.year = inYear;\n        return this;\n    }\n\n    /**\n     * Set the TimeZone for the Date that will be built by this builder (if \"null\", system default will be used)\n     */\n    public DateBuilder inTimeZone(TimeZone timezone) {\n        this.zoneId = timezone.toZoneId();\n        return this;\n    }\n\n    /**\n     * Set the Locale for the Date that will be built by this builder (if \"null\", system default will be used)\n     */\n    public DateBuilder inLocale(Locale locale) {\n        this.lc = locale;\n        return this;\n    }\n\n    public static Date futureDate(int interval, IntervalUnit unit) {\n        return futureDate(interval, unit, Clock.systemDefaultZone());\n    }\n\n    static Date futureDate(int interval, IntervalUnit unit, Clock clock) {\n        return Date.from(ZonedDateTime.now(clock).plus(interval, translate(unit)).toInstant());\n    }\n\n    private static ChronoUnit translate(IntervalUnit unit) {\n        switch (unit) {\n            case DAY : return ChronoUnit.DAYS;\n            case HOUR : return ChronoUnit.HOURS;\n            case MINUTE : return ChronoUnit.MINUTES;\n            case MONTH : return ChronoUnit.MONTHS;\n            case SECOND : return ChronoUnit.SECONDS;\n            case MILLISECOND : return ChronoUnit.MILLIS;\n            case WEEK : return ChronoUnit.WEEKS;\n            case YEAR : return ChronoUnit.YEARS;\n            default : throw new IllegalArgumentException(\"Unknown IntervalUnit\");\n        }\n    }\n\n    /**\n     * <p>\n     * Get a <code>Date</code> object that represents the given time, on\n     * tomorrow's date.\n     * </p>\n     *\n     * @param hour\n     *          The value (0-23) to give the hours field of the date\n     * @param minute\n     *          The value (0-59) to give the minutes field of the date\n     * @param second\n     *          The value (0-59) to give the seconds field of the date\n     * @return the new date\n     */\n    public static Date tomorrowAt(int hour, int minute, int second) {\n        return tomorrowAt(hour, minute, second, Clock.systemDefaultZone());\n    }\n\n    static Date tomorrowAt(int hour, int minute, int second, Clock clock) {\n        return Date.from(\n                ZonedDateTime.now(clock)\n                        .truncatedTo(ChronoUnit.DAYS)\n                        .plusHours(24)\n                        .with(LocalTime.of(hour, minute, second, 0))\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Get a <code>Date</code> object that represents the given time, on\n     * today's date (equivalent to {@link #dateOf(int, int, int)}).\n     * </p>\n     *\n     * @param hour\n     *          The value (0-23) to give the hours field of the date\n     * @param minute\n     *          The value (0-59) to give the minutes field of the date\n     * @param second\n     *          The value (0-59) to give the seconds field of the date\n     * @return the new date\n     */\n    public static Date todayAt(int hour, int minute, int second) {\n        return todayAt(hour, minute, second, Clock.systemDefaultZone());\n    }\n\n    static Date todayAt(int hour, int minute, int second, Clock clock) {\n        return dateOf(hour, minute, second, clock);\n    }\n\n    /**\n     * <p>\n     * Get a <code>Date</code> object that represents the given time, on\n     * today's date  (equivalent to {@link #todayAt(int, int, int)}).\n     * </p>\n     *\n     * @param hour\n     *          The value (0-23) to give the hours field of the date\n     * @param minute\n     *          The value (0-59) to give the minutes field of the date\n     * @param second\n     *          The value (0-59) to give the seconds field of the date\n     * @return the new date\n     */\n    public static Date dateOf(int hour, int minute, int second) {\n        return dateOf(hour, minute, second, Clock.systemDefaultZone());\n    }\n\n    static Date dateOf(int hour, int minute, int second, Clock clock) {\n        return Date.from(\n                ZonedDateTime.now(clock)\n                        .with(LocalTime.of(hour, minute, second, 0))\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Get a <code>Date</code> object that represents the given time, on the\n     * given date.\n     * </p>\n     *\n     * @param hour\n     *          The value (0-23) to give the hours field of the date\n     * @param minute\n     *          The value (0-59) to give the minutes field of the date\n     * @param second\n     *          The value (0-59) to give the seconds field of the date\n     * @param dayOfMonth\n     *          The value (1-31) to give the day of month field of the date\n     * @param month\n     *          The value (1-12) to give the month field of the date\n     * @return the new date\n     */\n    public static Date dateOf(int hour, int minute, int second,\n            int dayOfMonth, int month) {\n        return dateOf(hour, minute, second, dayOfMonth, month, Clock.systemDefaultZone());\n    }\n\n    static Date dateOf(int hour, int minute, int second,\n            int dayOfMonth, int month, Clock clock) {\n        var zdt = ZonedDateTime.now(clock);\n        return Date.from(\n                zdt.with(LocalDateTime.of(zdt.getYear(), month, dayOfMonth, hour, minute, second, 0))\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Get a <code>Date</code> object that represents the given time, on the\n     * given date.\n     * </p>\n     *\n     * @param hour\n     *          The value (0-23) to give the hours field of the date\n     * @param minute\n     *          The value (0-59) to give the minutes field of the date\n     * @param second\n     *          The value (0-59) to give the seconds field of the date\n     * @param dayOfMonth\n     *          The value (1-31) to give the day of month field of the date\n     * @param month\n     *          The value (1-12) to give the month field of the date\n     * @param year\n     *          The value (1970-999999999) to give the year field of the date\n     * @return the new date\n     */\n    public static Date dateOf(int hour, int minute, int second,\n            int dayOfMonth, int month, int year) {\n        return dateOf(hour, minute, second, dayOfMonth, month, year, Clock.systemDefaultZone());\n    }\n\n    static Date dateOf(int hour, int minute, int second,\n            int dayOfMonth, int month, int year, Clock clock) {\n        return Date.from(\n                LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, 0)\n                        .atZone(clock.getZone())\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even hour after the current time.\n     * </p>\n     *\n     * <p>\n     * For example a current time of 08:13:54 would result in a date\n     * with the time of 09:00:00. If the date's time is in the 23rd hour, the\n     * date's 'day' will be promoted, and the time will be set to 00:00:00.\n     * </p>\n     *\n     * @return the new rounded date\n     */\n    public static Date evenHourDateAfterNow() {\n        return evenHourDateAfterNow(Clock.systemDefaultZone());\n    }\n\n    static Date evenHourDateAfterNow(Clock clock) {\n        return evenHourDate(null, clock);\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even hour above the given\n     * date.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54 would result in a date\n     * with the time of 09:00:00. If the date's time is in the 23rd hour, the\n     * date's 'day' will be promoted, and the time will be set to 00:00:00.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenHourDate(Date date) {\n        return evenHourDate(date, Clock.systemDefaultZone());\n    }\n\n    static Date evenHourDate(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        zdt = zdt.plusHours(1);\n        return Date.from(\n                zdt.truncatedTo(ChronoUnit.HOURS)\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the previous even hour below the given\n     * date.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54 would result in a date\n     * with the time of 08:00:00.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenHourDateBefore(Date date) {\n        return evenHourDateBefore(date, Clock.systemDefaultZone());\n    }\n\n    static Date evenHourDateBefore(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        return Date.from(\n                zdt.truncatedTo(ChronoUnit.HOURS)\n                        .toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even minute after the current time.\n     * </p>\n     *\n     * <p>\n     * For example a current time of 08:13:54 would result in a date\n     * with the time of 08:14:00. If the date's time is in the 59th minute,\n     * then the hour (and possibly the day) will be promoted.\n     * </p>\n     *\n     * @return the new rounded date\n     */\n    public static Date evenMinuteDateAfterNow() {\n        return evenMinuteDateAfterNow(Clock.systemDefaultZone());\n    }\n\n    static Date evenMinuteDateAfterNow(Clock clock) {\n        return evenMinuteDate(null, clock);\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even minute above the given\n     * date.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54 would result in a date\n     * with the time of 08:14:00. If the date's time is in the 59th minute,\n     * then the hour (and possibly the day) will be promoted.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenMinuteDate(Date date) {\n        return evenMinuteDate(date, Clock.systemDefaultZone());\n    }\n\n    public static Date evenMinuteDate(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        zdt = zdt.plusMinutes(1);\n        return Date.from(zdt.truncatedTo(ChronoUnit.MINUTES).toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the previous even minute below the\n     * given date.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54 would result in a date\n     * with the time of 08:13:00.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenMinuteDateBefore(Date date) {\n        return evenMinuteDateBefore(date, Clock.systemDefaultZone());\n    }\n\n    static Date evenMinuteDateBefore(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        return Date.from(zdt.truncatedTo(ChronoUnit.MINUTES).toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even second after the current time.\n     * </p>\n     *\n     * @return the new rounded date\n     */\n    public static Date evenSecondDateAfterNow() {\n        return evenSecondDateAfterNow(Clock.systemDefaultZone());\n    }\n\n    static Date evenSecondDateAfterNow(Clock clock) {\n        return evenSecondDate(null, clock);\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even second above the given\n     * date.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenSecondDate(Date date) {\n        return evenSecondDate(date, Clock.systemDefaultZone());\n    }\n\n    static Date evenSecondDate(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        zdt = zdt.plusSeconds(1);\n        return Date.from(zdt.truncatedTo(ChronoUnit.SECONDS).toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the previous even second below the\n     * given date.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54.341 would result in a\n     * date with the time of 08:13:54.000.\n     * </p>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @return the new rounded date\n     */\n    public static Date evenSecondDateBefore(Date date) {\n        return evenSecondDateBefore(date, Clock.systemDefaultZone());\n    }\n\n    static Date evenSecondDateBefore(Date date, Clock clock) {\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n\n        return Date.from(zdt.truncatedTo(ChronoUnit.SECONDS).toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even multiple of the given\n     * minute.\n     * </p>\n     *\n     * <p>\n     * For example an input date with a time of 08:13:54, and an input\n     * minute-base of 5 would result in a date with the time of 08:15:00. The\n     * same input date with an input minute-base of 10 would result in a date\n     * with the time of 08:20:00. But a date with the time 08:53:31 and an\n     * input minute-base of 45 would result in 09:00:00, because the even-hour\n     * is the next 'base' for 45-minute intervals.\n     * </p>\n     *\n     * <p>\n     * More examples:\n     * </p>\n     * <table>\n     * <caption>Examples of inputs and corresponding outputs.</caption>\n     * <tr>\n     * <th>Input Time</th>\n     * <th>Minute-Base</th>\n     * <th>Result Time</th>\n     * </tr>\n     * <tr>\n     * <td>11:16:41</td>\n     * <td>20</td>\n     * <td>11:20:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:36:41</td>\n     * <td>20</td>\n     * <td>11:40:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:46:41</td>\n     * <td>20</td>\n     * <td>12:00:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:26:41</td>\n     * <td>30</td>\n     * <td>11:30:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:36:41</td>\n     * <td>30</td>\n     * <td>12:00:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:16:41</td>\n     * <td>17</td>\n     * <td>11:17:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:17:41</td>\n     * <td>17</td>\n     * <td>11:34:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:52:41</td>\n     * <td>17</td>\n     * <td>12:00:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:52:41</td>\n     * <td>5</td>\n     * <td>11:55:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:57:41</td>\n     * <td>5</td>\n     * <td>12:00:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:17:41</td>\n     * <td>0</td>\n     * <td>12:00:00</td>\n     * </tr>\n     * <tr>\n     * <td>11:17:41</td>\n     * <td>1</td>\n     * <td>11:08:00</td>\n     * </tr>\n     * </table>\n     *\n     * @param date\n     *          the Date to round, if <code>null</code> the current time will\n     *          be used\n     * @param minuteBase\n     *          the base-minute to set the time on\n     * @return the new rounded date\n     *\n     * @see #nextGivenSecondDate(Date, int)\n     */\n    public static Date nextGivenMinuteDate(Date date, int minuteBase) {\n        return nextGivenMinuteDate(date, minuteBase, Clock.systemDefaultZone());\n    }\n\n    static Date nextGivenMinuteDate(Date date, int minuteBase, Clock clock) {\n        if (minuteBase < 0 || minuteBase > 59) {\n            throw new IllegalArgumentException(\n                    \"minuteBase must be >=0 and <= 59\");\n        }\n\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n        if (minuteBase == 0) {\n            zdt = zdt.truncatedTo(ChronoUnit.HOURS).plusHours(1);\n            return Date.from(zdt.toInstant());\n        }\n\n        zdt = zdt.truncatedTo(ChronoUnit.MINUTES);\n        int minute = zdt.getMinute();\n        int nextminute = minute + minuteBase - (minute % minuteBase);\n\n        if (nextminute >= 60) {\n            zdt = zdt.truncatedTo(ChronoUnit.HOURS).plusHours(1);\n        } else {\n            zdt = zdt.withMinute(nextminute);\n        }\n\n        return Date.from(zdt.toInstant());\n    }\n\n    /**\n     * <p>\n     * Returns a date that is rounded to the next even multiple of the given\n     * second.\n     * </p>\n     *\n     * <p>\n     * The rules for calculating the second are the same as those for\n     * calculating the minute in the method\n     * <code>getNextGivenMinuteDate(..)</code>.\n     * </p>\n     *\n     * @param date the Date to round, if <code>null</code> the current time will\n     * be used\n     * @param secondBase the base-second to set the time on\n     * @return the new rounded date\n     *\n     * @see #nextGivenMinuteDate(Date, int)\n     */\n    public static Date nextGivenSecondDate(Date date, int secondBase) {\n        return nextGivenSecondDate(date, secondBase, Clock.systemDefaultZone());\n    }\n\n    static Date nextGivenSecondDate(Date date, int secondBase, Clock clock) {\n        if (secondBase < 0 || secondBase > 59) {\n            throw new IllegalArgumentException(\n                    \"secondBase must be >=0 and <= 59\");\n        }\n\n        var zdt = (date == null) ? ZonedDateTime.now(clock) : ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);\n        if (secondBase == 0) {\n            zdt = zdt.truncatedTo(ChronoUnit.MINUTES).plusMinutes(1);\n            return Date.from(zdt.toInstant());\n        }\n\n        zdt = zdt.truncatedTo(ChronoUnit.SECONDS);\n        int second = zdt.getSecond();\n        int nextSecond = second + secondBase - (second % secondBase);\n\n        if (nextSecond >= 60) {\n            zdt = zdt.truncatedTo(ChronoUnit.MINUTES).plusMinutes(1);\n        } else {\n            zdt = zdt.withSecond(nextSecond);\n        }\n\n        return Date.from(zdt.toInstant());\n    }\n\n    /**\n     * Translate a date and time from a users time zone to the another\n     * (probably server) time zone to assist in creating a simple trigger with\n     * the right date and time.\n     *\n     * @param date the date to translate\n     * @param src the original time-zone\n     * @param dest the destination time-zone\n     * @return the translated date\n     */\n    public static Date translateTime(Date date, TimeZone src, TimeZone dest) {\n        Date newDate = new Date();\n        int offset = (dest.getOffset(date.getTime()) - src.getOffset(date.getTime()));\n        newDate.setTime(date.getTime() - offset);\n\n        return newDate;\n    }\n\n    ////////////////////////////////////////////////////////////////////////////////////////////////////\n\n    public static void validateDayOfWeek(int dayOfWeek) {\n        if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {\n            throw new IllegalArgumentException(\"Invalid day of week.\");\n        }\n    }\n\n    public static void validateHour(int hour) {\n        if (hour < 0 || hour > 23) {\n            throw new IllegalArgumentException(\n                    \"Invalid hour (must be >= 0 and <= 23).\");\n        }\n    }\n\n    public static void validateMinute(int minute) {\n        if (minute < 0 || minute > 59) {\n            throw new IllegalArgumentException(\n                    \"Invalid minute (must be >= 0 and <= 59).\");\n        }\n    }\n\n    public static void validateSecond(int second) {\n        if (second < 0 || second > 59) {\n            throw new IllegalArgumentException(\n                    \"Invalid second (must be >= 0 and <= 59).\");\n        }\n    }\n\n    public static void validateDayOfMonth(int day) {\n        if (day < 1 || day > 31) {\n            throw new IllegalArgumentException(\"Invalid day of month.\");\n        }\n    }\n\n    public static void validateMonth(int month) {\n        if (month < 1 || month > 12) {\n            throw new IllegalArgumentException(\n                    \"Invalid month (must be >= 1 and <= 12.\");\n        }\n    }\n\n    public static void validateYear(int year) {\n        if (year < 1970 || year > Year.MAX_VALUE) {\n            throw new IllegalArgumentException(\n                    \"Invalid year (must be >= 0 and <= \" + Year.MAX_VALUE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/DisallowConcurrentExecution.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that marks a {@link Job} class as one that must not have multiple\n * instances executed concurrently (where instance is based-upon a {@link JobDetail} \n * definition - or in other words based upon a {@link JobKey}).\n *\n * @see PersistJobDataAfterExecution\n * \n * @author jhouse\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface DisallowConcurrentExecution {\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ExecuteInJTATransaction.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.transaction.UserTransaction;\n\n/**\n * An annotation that marks a {@link Job} class as one that will have its \n * execution wrapped by a JTA Transaction. \n *   \n * <p>If this annotation is present, Quartz will begin a JTA transaction \n * before calling the <code>execute()</code> method, and will commit\n * the transaction if the method does not throw an exception and the\n * transaction has not had <code>setRollbackOnly()</code> called on it \n * (otherwise the transaction will be rolled-back by Quartz).</p>\n * \n * <p>This is essentially the same behavior as setting the configuration\n * property <code>org.quartz.scheduler.wrapJobExecutionInUserTransaction</code>\n * to <code>true</code> - except that it only affects the job that has\n * the annotation, rather than all jobs (as the property does).  If the\n * property is set to <code>true</code> and the annotation is also set,\n * then of course the annotation becomes redundant.</p> \n * \n * @author jhouse\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface ExecuteInJTATransaction {\n\n  /**\n   * The JTA transaction timeout.\n   * <p>\n   * If set then the {@code UserTransaction} timeout will be set to this\n   * value before beginning the transaction.\n   * \n   * @see UserTransaction#setTransactionTimeout(int) \n   * @return the transaction timeout.\n   */\n  int timeout() default -1;\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/InterruptableJob.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * The interface to be implemented by <code>{@link Job}s</code> that provide a \n * mechanism for having their execution interrupted.  It is NOT a requirement\n * for jobs to implement this interface - in fact, for most people, none of\n * their jobs will.\n * \n * <p>Interrupting a <code>Job</code> is very analogous in concept and \n * challenge to normal interruption of a <code>Thread</code> in Java. \n * \n * <p>\n * The means of actually interrupting the Job must be implemented within the\n * <code>Job</code> itself (the <code>interrupt()</code> method of this \n * interface is simply a means for the scheduler to inform the <code>Job</code>\n * that a request has been made for it to be interrupted). The mechanism that\n * your jobs use to interrupt themselves might vary between implementations.\n * However the principle idea in any implementation should be to have the\n * body of the job's <code>execute(..)</code> periodically check some flag to\n * see if an interruption has been requested, and if the flag is set, somehow\n * abort the performance of the rest of the job's work.  An example of \n * interrupting a job can be found in the java source for the  class \n * <code>org.quartz.examples.DumbInterruptableJob</code>.  It is legal to use\n * some combination of <code>wait()</code> and <code>notify()</code> \n * synchronization within <code>interrupt()</code> and <code>execute(..)</code>\n * in order to have the <code>interrupt()</code> method block until the\n * <code>execute(..)</code> signals that it has noticed the set flag.\n * </p>\n * \n * <p>\n * If the Job performs some form of blocking I/O or similar functions, you may\n * want to consider having the <code>Job.execute(..)</code> method store a\n * reference to the calling <code>Thread</code> as a member variable.  Then the\n * Implementation of this interfaces <code>interrupt()</code> method can call \n * <code>interrupt()</code> on that Thread.   Before attempting this, make\n * sure that you fully understand what <code>java.lang.Thread.interrupt()</code> \n * does and doesn't do.  Also make sure that you clear the Job's member \n * reference to the Thread when the execute(..) method exits (preferably in a\n * <code>finally</code> block.\n * </p>\n * \n * <p>\n * See Example 7 (org.quartz.examples.example7.DumbInterruptableJob) for a simple\n * implementation demonstration.\n * </p>\n * @see Job\n * @see StatefulJob\n * @see Scheduler#interrupt(JobKey)\n * @see Scheduler#interrupt(String)\n * \n * @author James House\n */\npublic interface InterruptableJob extends Job {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a user\n     * interrupts the <code>Job</code>.\n     * </p>\n     * \n     * @throws UnableToInterruptJobException\n     *           if there is an exception while interrupting the job.\n     */\n    void interrupt()\n        throws UnableToInterruptJobException;\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/Job.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * <p>\n * The interface to be implemented by classes which represent a 'job' to be\n * performed.\n * </p>\n * \n * <p>\n * Instances of <code>Job</code> must have a <code>public</code>\n * no-argument constructor.\n * </p>\n * \n * <p>\n * <code>JobDataMap</code> provides a mechanism for 'instance member data'\n * that may be required by some implementations of this interface.\n * </p>\n * \n * @see JobDetail\n * @see JobBuilder\n * @see ExecuteInJTATransaction\n * @see DisallowConcurrentExecution\n * @see PersistJobDataAfterExecution\n * @see Trigger\n * @see Scheduler\n * \n * @author James House\n */\npublic interface Job {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * fires that is associated with the <code>Job</code>.\n     * </p>\n     * \n     * <p>\n     * The implementation may wish to set a \n     * {@link JobExecutionContext#setResult(Object) result} object on the \n     * {@link JobExecutionContext} before this method exits.  The result itself\n     * is meaningless to Quartz, but may be informative to \n     * <code>{@link JobListener}s</code> or \n     * <code>{@link TriggerListener}s</code> that are watching the job's \n     * execution.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *           if there is an exception while executing the job.\n     */\n    void execute(JobExecutionContext context)\n        throws JobExecutionException;\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.impl.JobDetailImpl;\nimport org.quartz.utils.Key;\n\n/**\n * <code>JobBuilder</code> is used to instantiate {@link JobDetail}s.\n * \n * <p>The builder will always try to keep itself in a valid state, with \n * reasonable defaults set for calling build() at any point.  For instance\n * if you do not invoke <i>withIdentity(..)</i> a job name will be generated\n * for you.</p>\n *   \n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *  \n * @see TriggerBuilder\n * @see DateBuilder \n * @see JobDetail\n */\npublic class JobBuilder {\n\n    private JobKey key;\n    private String description;\n    private Class<? extends Job> jobClass;\n    private boolean durability;\n    private boolean shouldRecover;\n    \n    private JobDataMap jobDataMap = new JobDataMap();\n    \n    protected JobBuilder() {\n    }\n    \n    /**\n     * Create a JobBuilder with which to define a <code>JobDetail</code>.\n     * \n     * @return a new JobBuilder\n     */\n    public static JobBuilder newJob() {\n        return new JobBuilder();\n    }\n    \n    /**\n     * Create a JobBuilder with which to define a <code>JobDetail</code>,\n     * and set the class name of the <code>Job</code> to be executed.\n     * \n     * @return a new JobBuilder\n     */\n    public static JobBuilder newJob(Class <? extends Job> jobClass) {\n        JobBuilder b = new JobBuilder();\n        b.ofType(jobClass);\n        return b;\n    }\n\n    /**\n     * Produce the <code>JobDetail</code> instance defined by this \n     * <code>JobBuilder</code>.\n     * \n     * @return the defined JobDetail.\n     */\n    public JobDetail build() {\n\n        JobDetailImpl job = new JobDetailImpl();\n        \n        job.setJobClass(jobClass);\n        job.setDescription(description);\n        if(key == null)\n            key = new JobKey(Key.createUniqueName(null), null);\n        job.setKey(key); \n        job.setDurability(durability);\n        job.setRequestsRecovery(shouldRecover);\n        \n        \n        if(!jobDataMap.isEmpty())\n            job.setJobDataMap(jobDataMap);\n        \n        return job;\n    }\n    \n    /**\n     * Use a <code>JobKey</code> with the given name and default group to\n     * identify the JobDetail.\n     * \n     * <p>If none of the 'withIdentity' methods are set on the JobBuilder,\n     * then a random, unique JobKey will be generated.</p>\n     * \n     * @param name the name element for the Job's JobKey\n     * @return the updated JobBuilder\n     * @see JobKey\n     * @see JobDetail#getKey()\n     */\n    public JobBuilder withIdentity(String name) {\n        key = new JobKey(name, null);\n        return this;\n    }  \n    \n    /**\n     * Use a <code>JobKey</code> with the given name and group to\n     * identify the JobDetail.\n     * \n     * <p>If none of the 'withIdentity' methods are set on the JobBuilder,\n     * then a random, unique JobKey will be generated.</p>\n     * \n     * @param name the name element for the Job's JobKey\n     * @param group the group element for the Job's JobKey\n     * @return the updated JobBuilder\n     * @see JobKey\n     * @see JobDetail#getKey()\n     */\n    public JobBuilder withIdentity(String name, String group) {\n        key = new JobKey(name, group);\n        return this;\n    }\n    \n    /**\n     * Use a <code>JobKey</code> to identify the JobDetail.\n     * \n     * <p>If none of the 'withIdentity' methods are set on the JobBuilder,\n     * then a random, unique JobKey will be generated.</p>\n     * \n     * @param jobKey the Job's JobKey\n     * @return the updated JobBuilder\n     * @see JobKey\n     * @see JobDetail#getKey()\n     */\n    public JobBuilder withIdentity(JobKey jobKey) {\n        this.key = jobKey;\n        return this;\n    }\n    \n    /**\n     * Set the given (human-meaningful) description of the Job.\n     * \n     * @param jobDescription the description for the Job\n     * @return the updated JobBuilder\n     * @see JobDetail#getDescription()\n     */\n    public JobBuilder withDescription(String jobDescription) {\n        this.description = jobDescription;\n        return this;\n    }\n    \n    /**\n     * Set the class which will be instantiated and executed when a\n     * Trigger fires that is associated with this JobDetail.\n     * \n     * @param jobClazz a class implementing the Job interface.\n     * @return the updated JobBuilder\n     * @see JobDetail#getJobClass()\n     */\n    public JobBuilder ofType(Class <? extends Job> jobClazz) {\n        this.jobClass = jobClazz;\n        return this;\n    }\n\n    /**\n     * Instructs the <code>Scheduler</code> whether or not the <code>Job</code>\n     * should be re-executed if a 'recovery' or 'fail-over' situation is\n     * encountered.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * - this method sets the value to <code>true</code>.\n     * </p>\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#requestsRecovery()\n     */\n    public JobBuilder requestRecovery() {\n        this.shouldRecover = true;\n        return this;\n    }\n\n    /**\n     * Instructs the <code>Scheduler</code> whether or not the <code>Job</code>\n     * should be re-executed if a 'recovery' or 'fail-over' situation is\n     * encountered.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     * \n     * @param jobShouldRecover the desired setting\n     * @return the updated JobBuilder\n     */\n    public JobBuilder requestRecovery(boolean jobShouldRecover) {\n        this.shouldRecover = jobShouldRecover;\n        return this;\n    }\n\n    /**\n     * Whether or not the <code>Job</code> should remain stored after it is\n     * orphaned (no <code>{@link Trigger}s</code> point to it).\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code> \n     * - this method sets the value to <code>true</code>.\n     * </p>\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#isDurable()\n     */\n    public JobBuilder storeDurably() {\n        return storeDurably(true);\n    }\n    \n    /**\n     * Whether or not the <code>Job</code> should remain stored after it is\n     * orphaned (no <code>{@link Trigger}s</code> point to it).\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     * \n     * @param jobDurability the value to set for the durability property.\n     * @return the updated JobBuilder\n     * @see JobDetail#isDurable()\n     */\n    public JobBuilder storeDurably(boolean jobDurability) {\n        this.durability = jobDurability;\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, String value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, Integer value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, Long value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, Float value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, Double value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the JobDetail's {@link JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(String dataKey, Boolean value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add all the data from the given {@link JobDataMap} to the\n     * {@code JobDetail}'s {@code JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap()\n     */\n    public JobBuilder usingJobData(JobDataMap newJobDataMap) {\n        jobDataMap.putAll(newJobDataMap);\n        return this;\n    }\n\n    /**\n     * Replace the {@code JobDetail}'s {@link JobDataMap} with the\n     * given {@code JobDataMap}.\n     * \n     * @return the updated JobBuilder\n     * @see JobDetail#getJobDataMap() \n     */\n    public JobBuilder setJobData(JobDataMap newJobDataMap) {\n        jobDataMap = newJobDataMap;\n        return this;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobDataMap.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\nimport org.quartz.utils.StringKeyDirtyFlagMap;\n\n/**\n * Holds state information for <code>Job</code> instances.\n * \n * <p>\n * <code>JobDataMap</code> instances are stored once when the <code>Job</code>\n * is added to a scheduler. They are also re-persisted after every execution of\n * jobs annotated with <code>@PersistJobDataAfterExecution</code>.\n * </p>\n * \n * <p>\n * <code>JobDataMap</code> instances can also be stored with a \n * <code>Trigger</code>.  This can be useful in the case where you have a Job\n * that is stored in the scheduler for regular/repeated use by multiple \n * Triggers, yet with each independent triggering, you want to supply the\n * Job with different data inputs.  \n * </p>\n * \n * <p>\n * The <code>JobExecutionContext</code> passed to a Job at execution time \n * also contains a convenience <code>JobDataMap</code> that is the result\n * of merging the contents of the trigger's JobDataMap (if any) over the\n * Job's JobDataMap (if any).  \n * </p>\n *\n * <p>\n * Update since 2.2.4 - We keep an dirty flag for this map so that whenever you modify(add/delete) any of the entries,\n * it will set to \"true\". However if you create new instance using an existing map with {@link #JobDataMap(Map)}, then\n * the dirty flag will NOT be set to \"true\" until you modify the instance.\n * </p>\n * \n * @see Job\n * @see PersistJobDataAfterExecution\n * @see Trigger\n * @see JobExecutionContext\n * \n * @author James House\n */\npublic class JobDataMap extends StringKeyDirtyFlagMap implements Serializable {\n\n    private static final long serialVersionUID = -6939901990106713909L;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create an empty <code>JobDataMap</code>.\n     * </p>\n     */\n    public JobDataMap() {\n        super(15);\n    }\n\n    /**\n     * <p>\n     * Create a <code>JobDataMap</code> with the given data.\n     * </p>\n     */\n    public JobDataMap(Map<?, ?> map) {\n        this();\n        @SuppressWarnings(\"unchecked\") // casting to keep API compatible and avoid compiler errors/warnings.\n        Map<String, Object> mapTyped = (Map<String, Object>)map;\n        putAll(mapTyped);\n\n        // When constructing a new data map from another existing map, we should NOT mark dirty flag as true\n        // Use case: loading JobDataMap from DB\n        clearDirtyFlag();\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Adds the given <code>boolean</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, boolean value) {\n        String strValue = Boolean.valueOf(value).toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Boolean</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Boolean value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>char</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, char value) {\n        String strValue = Character.valueOf(value).toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Character</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Character value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>double</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, double value) {\n        String strValue = Double.toString(value);\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Double</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Double value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>float</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, float value) {\n        String strValue = Float.toString(value);\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Float</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Float value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>int</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, int value) {\n        String strValue = Integer.valueOf(value).toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Integer</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Integer value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>long</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, long value) {\n        String strValue = Long.valueOf(value).toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Long</code> value as a string version to the\n     * <code>Job</code>'s data map.\n     * </p>\n     */\n    public void putAsString(String key, Long value) {\n        String strValue = value.toString();\n\n        super.put(key, strValue);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>int</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public int getIntFromString(String key) {\n        Object obj = get(key);\n\n        return Integer.parseInt((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>int</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String or Integer.\n     */\n    public int getIntValue(String key) {\n        Object obj = get(key);\n\n        if(obj instanceof String) {\n            return getIntFromString(key);\n        } else {\n            return getInt(key);\n        }\n    }\n    \n    /**\n     * <p>\n     * Retrieve the identified <code>int</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Integer getIntegerFromString(String key) {\n        Object obj = get(key);\n\n        return Integer.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>boolean</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public boolean getBooleanValueFromString(String key) {\n        Object obj = get(key);\n\n        return Boolean.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>boolean</code> value from the \n     * <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String or Boolean.\n     */\n    public boolean getBooleanValue(String key) {\n        Object obj = get(key);\n\n        if(obj instanceof String) {\n            return getBooleanValueFromString(key);\n        } else {\n            return getBoolean(key);\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>Boolean</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Boolean getBooleanFromString(String key) {\n        Object obj = get(key);\n\n        return Boolean.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>char</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public char getCharFromString(String key) {\n        Object obj = get(key);\n\n        return ((String) obj).charAt(0);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>Character</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Character getCharacterFromString(String key) {\n        Object obj = get(key);\n\n        return ((String) obj).charAt(0);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>double</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public double getDoubleValueFromString(String key) {\n        Object obj = get(key);\n\n        return Double.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>double</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String or Double.\n     */\n    public double getDoubleValue(String key) {\n        Object obj = get(key);\n\n        if(obj instanceof String) {\n            return getDoubleValueFromString(key);\n        } else {\n            return getDouble(key);\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>Double</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Double getDoubleFromString(String key) {\n        Object obj = get(key);\n\n        return Double.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>float</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public float getFloatValueFromString(String key) {\n        Object obj = get(key);\n\n        return Float.parseFloat((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>float</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String or Float.\n     */\n    public float getFloatValue(String key) {\n        Object obj = get(key);\n\n        if(obj instanceof String) {\n            return getFloatValueFromString(key);\n        } else {\n            return getFloat(key);\n        }\n    }\n    \n    /**\n     * <p>\n     * Retrieve the identified <code>Float</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Float getFloatFromString(String key) {\n        Object obj = get(key);\n\n        return Float.valueOf((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>long</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public long getLongValueFromString(String key) {\n        Object obj = get(key);\n\n        return Long.parseLong((String) obj);\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>long</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String or Long.\n     */\n    public long getLongValue(String key) {\n        Object obj = get(key);\n\n        if(obj instanceof String) {\n            return getLongValueFromString(key);\n        } else {\n            return getLong(key);\n        }\n    }\n    \n    /**\n     * <p>\n     * Retrieve the identified <code>Long</code> value from the <code>JobDataMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public Long getLongFromString(String key) {\n        Object obj = get(key);\n\n        return Long.valueOf((String) obj);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobDetail.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\n\n/**\n * Conveys the detail properties of a given <code>Job</code> instance. JobDetails are\n * to be created/defined with {@link JobBuilder}.\n * \n * <p>\n * Quartz does not store an actual instance of a <code>Job</code> class, but\n * instead allows you to define an instance of one, through the use of a <code>JobDetail</code>.\n * </p>\n * \n * <p>\n * <code>Job</code>s have a name and group associated with them, which\n * should uniquely identify them within a single <code>{@link Scheduler}</code>.\n * </p>\n * \n * <p>\n * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code>s\n * are scheduled. Many <code>Trigger</code>s can point to the same <code>Job</code>,\n * but a single <code>Trigger</code> can only point to one <code>Job</code>.\n * </p>\n * \n * @see JobBuilder\n * @see Job\n * @see JobDataMap\n * @see Trigger\n * \n * @author James House\n */\npublic interface JobDetail extends Serializable, Cloneable {\n\n    JobKey getKey();\n\n    /**\n     * <p>\n     * Return the description given to the <code>Job</code> instance by its\n     * creator (if any).\n     * </p>\n     * \n     * @return null if no description was set.\n     */\n    String getDescription();\n\n    /**\n     * <p>\n     * Get the instance of <code>Job</code> that will be executed.\n     * </p>\n     */\n    Class<? extends Job> getJobClass();\n\n    /**\n     * <p>\n     * Get the <code>JobDataMap</code> that is associated with the <code>Job</code>.\n     * </p>\n     */\n    JobDataMap getJobDataMap();\n\n    /**\n     * <p>\n     * Whether or not the <code>Job</code> should remain stored after it is\n     * orphaned (no <code>{@link Trigger}s</code> point to it).\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     * \n     * @return <code>true</code> if the Job should remain persisted after\n     *         being orphaned.\n     */\n    boolean isDurable();\n\n    /**\n     * @see PersistJobDataAfterExecution\n     * @return whether the associated Job class carries the {@link PersistJobDataAfterExecution} annotation.\n     */\n    boolean isPersistJobDataAfterExecution();\n\n    /**\n     * @see DisallowConcurrentExecution\n     * @return whether the associated Job class carries the {@link DisallowConcurrentExecution} annotation.\n     */\n    boolean isConcurrentExecutionDisallowed();\n\n    /**\n     * <p>\n     * Instructs the <code>Scheduler</code> whether or not the <code>Job</code>\n     * should be re-executed if a 'recovery' or 'fail-over' situation is\n     * encountered.\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     * \n     * @see JobExecutionContext#isRecovering()\n     */\n    boolean requestsRecovery();\n\n    Object clone();\n    \n    /**\n     * Get a {@link JobBuilder} that is configured to produce a \n     * <code>JobDetail</code> identical to this one.\n     */\n    JobBuilder getJobBuilder();\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobExecutionContext.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Date;\n\n/**\n * A context bundle containing handles to various environment information, that\n * is given to a <code>{@link org.quartz.JobDetail}</code> instance as it is\n * executed, and to a <code>{@link Trigger}</code> instance after the\n * execution completes.\n * \n * <p>\n * The <code>JobDataMap</code> found on this object (via the \n * <code>getMergedJobDataMap()</code> method) serves as a convenience -\n * it is a merge of the <code>JobDataMap</code> found on the \n * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with \n * the value in the latter overriding any same-named values in the former.\n * <i>It is thus considered a 'best practice' that the execute code of a Job\n * retrieve data from the JobDataMap found on this object</i>  NOTE: Do not\n * expect value 'set' into this JobDataMap to somehow be set back onto a\n * job's own JobDataMap  - even if it has the\n * <code>@PersistJobDataAfterExecution</code> annotation.\n * </p>\n * \n * <p>\n * <code>JobExecutionContext</code> s are also returned from the \n * <code>Scheduler.getCurrentlyExecutingJobs()</code>\n * method. These are the same instances as those passed into the jobs that are\n * currently executing within the scheduler. The exception to this is when your\n * application is using Quartz remotely (i.e. via RMI) - in which case you get\n * a clone of the <code>JobExecutionContext</code>s, and their references to\n * the <code>Scheduler</code> and <code>Job</code> instances have been lost (a\n * clone of the <code>JobDetail</code> is still available - just not a handle\n * to the job instance that is running).\n * </p>\n * \n * @see #getScheduler()\n * @see #getMergedJobDataMap()\n * @see #getJobDetail()\n * \n * @see Job\n * @see Trigger\n * @see JobDataMap\n * \n * @author James House\n */\npublic interface JobExecutionContext {\n\n    /**\n     * <p>\n     * Get a handle to the <code>Scheduler</code> instance that fired the\n     * <code>Job</code>.\n     * </p>\n     */\n    Scheduler getScheduler();\n\n    /**\n     * <p>\n     * Get a handle to the <code>Trigger</code> instance that fired the\n     * <code>Job</code>.\n     * </p>\n     */\n    Trigger getTrigger();\n\n    /**\n     * <p>\n     * Get a handle to the <code>Calendar</code> referenced by the <code>Trigger</code>\n     * instance that fired the <code>Job</code>.\n     * </p>\n     */\n    Calendar getCalendar();\n\n    /**\n     * <p>\n     * If the <code>Job</code> is being re-executed because of a 'recovery'\n     * situation, this method will return <code>true</code>.\n     * </p>\n     */\n    boolean isRecovering();\n\n    /**\n     * Return the {@code TriggerKey} of the originally scheduled and now recovering job.\n     * <p>\n     * When recovering a previously failed job execution this method returns the identity\n     * of the originally firing trigger.  This recovering job will have been scheduled for\n     * the same firing time as the original job, and so is available via the\n     * {@link #getScheduledFireTime()} method.  The original firing time of the job can be\n     * accessed via the {@link Scheduler#FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS}\n     * element of this job's {@code JobDataMap}.\n     * \n     * @return the recovering trigger details\n     * @throws IllegalStateException if this is not a recovering job.\n     */\n    TriggerKey getRecoveringTriggerKey() throws IllegalStateException;\n\n    int getRefireCount();\n\n    /**\n     * <p>\n     * Get the convenience <code>JobDataMap</code> of this execution context.\n     * </p>\n     * \n     * <p>\n     * The <code>JobDataMap</code> found on this object serves as a convenience -\n     * it is a merge of the <code>JobDataMap</code> found on the \n     * <code>JobDetail</code> and the one found on the <code>Trigger</code>, with \n     * the value in the latter overriding any same-named values in the former.\n     * <i>It is thus considered a 'best practice' that the execute code of a Job\n     * retrieve data from the JobDataMap found on this object.</i>\n     * </p>\n     * \n     * <p>NOTE: Do not expect value 'set' into this JobDataMap to somehow be set\n     * or persisted back onto a job's own JobDataMap - even if it has the\n     * <code>@PersistJobDataAfterExecution</code> annotation.\n     * </p>\n     * \n     * <p>\n     * Attempts to change the contents of this map typically result in an \n     * <code>IllegalStateException</code>.\n     * </p>\n     * \n     */\n    JobDataMap getMergedJobDataMap();\n\n    /**\n     * <p>\n     * Get the <code>JobDetail</code> associated with the <code>Job</code>.\n     * </p>\n     */\n    JobDetail getJobDetail();\n\n    /**\n     * <p>\n     * Get the instance of the <code>Job</code> that was created for this\n     * execution.\n     * </p>\n     * \n     * <p>\n     * Note: The Job instance is not available through remote scheduler\n     * interfaces.\n     * </p>\n     */\n    Job getJobInstance();\n\n    /**\n     * The actual time the trigger fired. For instance the scheduled time may\n     * have been 10:00:00 but the actual fire time may have been 10:00:03 if\n     * the scheduler was too busy.\n     * \n     * @return Returns the fireTime.\n     * @see #getScheduledFireTime()\n     */\n    Date getFireTime();\n\n    /**\n     * The scheduled time the trigger fired for. For instance the scheduled\n     * time may have been 10:00:00 but the actual fire time may have been\n     * 10:00:03 if the scheduler was too busy.\n     * \n     * @return Returns the scheduledFireTime.\n     * @see #getFireTime()\n     */\n    Date getScheduledFireTime();\n\n    Date getPreviousFireTime();\n\n    Date getNextFireTime();\n\n    /**\n     * Get the unique Id that identifies this particular firing instance of the\n     * trigger that triggered this job execution.  It is unique to this \n     * JobExecutionContext instance as well.\n     * \n     * @return the unique fire instance id\n     * @see Scheduler#interrupt(String)\n     */\n    String getFireInstanceId();\n    \n    /**\n     * Returns the result (if any) that the <code>Job</code> set before its \n     * execution completed (the type of object set as the result is entirely up \n     * to the particular job).\n     * \n     * <p>\n     * The result itself is meaningless to Quartz, but may be informative\n     * to <code>{@link JobListener}s</code> or \n     * <code>{@link TriggerListener}s</code> that are watching the job's \n     * execution.\n     * </p> \n     * \n     * @return Returns the result.\n     */\n    Object getResult();\n\n    /**\n     * Set the result (if any) of the <code>Job</code>'s execution (the type of \n     * object set as the result is entirely up to the particular job).\n     * \n     * <p>\n     * The result itself is meaningless to Quartz, but may be informative\n     * to <code>{@link JobListener}s</code> or \n     * <code>{@link TriggerListener}s</code> that are watching the job's \n     * execution.\n     * </p> \n     */\n    void setResult(Object result);\n\n    /**\n     * The amount of time the job ran for (in milliseconds).  The returned \n     * value will be -1 until the job has actually completed (or thrown an \n     * exception), and is therefore generally only useful to \n     * <code>JobListener</code>s and <code>TriggerListener</code>s.\n     * \n     * @return Returns the jobRunTime.\n     */\n    long getJobRunTime();\n\n    /**\n     * Put the specified value into the context's data map with the given key.\n     * Possibly useful for sharing data between listeners and jobs.\n     *\n     * <p>NOTE: this data is volatile - it is lost after the job execution\n     * completes, and all TriggerListeners and JobListeners have been \n     * notified.</p> \n     *  \n     * @param key the key for the associated value\n     * @param value the value to store\n     */\n    void put(Object key, Object value);\n\n    /**\n     * Get the value with the given key from the context's data map.\n     * \n     * @param key the key for the desired value\n     */\n    Object get(Object key);\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobExecutionException.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An exception that can be thrown by a <code>{@link org.quartz.Job}</code>\n * to indicate to the Quartz <code>{@link Scheduler}</code> that an error\n * occurred while executing, and whether or not the <code>Job</code> requests\n * to be re-fired immediately (using the same <code>{@link JobExecutionContext}</code>,\n * or whether it wants to be unscheduled.\n * \n * <p>\n * Note that if the flag for 'refire immediately' is set, the flags for\n * unscheduling the Job are ignored.\n * </p>\n * \n * @see Job\n * @see JobExecutionContext\n * @see SchedulerException\n * \n * @author James House\n */\npublic class JobExecutionException extends SchedulerException {\n\n    private static final long serialVersionUID = 1326342535829043325L;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private boolean refire = false;\n\n    private boolean unscheduleTrigg = false;\n\n    private boolean unscheduleAllTriggs = false;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a JobExecutionException, with the 're-fire immediately' flag set\n     * to <code>false</code>.\n     * </p>\n     */\n    public JobExecutionException() {\n    }\n\n    /**\n     * <p>\n     * Create a JobExecutionException, with the given cause.\n     * </p>\n     */\n    public JobExecutionException(Throwable cause) {\n        super(cause);\n    }\n\n    /**\n     * <p>\n     * Create a JobExecutionException, with the given message.\n     * </p>\n     */\n    public JobExecutionException(String msg) {\n        super(msg);\n    }\n\n    /**\n     * <p>\n     * Create a JobExecutionException with the 're-fire immediately' flag set\n     * to the given value.\n     * </p>\n     */\n    public JobExecutionException(boolean refireImmediately) {\n        refire = refireImmediately;\n    }\n\n    /**\n     * <p>\n     * Create a JobExecutionException with the given underlying exception, and\n     * the 're-fire immediately' flag set to the given value.\n     * </p>\n     */\n    public JobExecutionException(Throwable cause, boolean refireImmediately) {\n        super(cause);\n\n        refire = refireImmediately;\n    }\n\n    /**\n     * <p>\n     * Create a JobExecutionException with the given message, and underlying\n     * exception.\n     * </p>\n     */\n    public JobExecutionException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n    \n    /**\n     * <p>\n     * Create a JobExecutionException with the given message, and underlying\n     * exception, and the 're-fire immediately' flag set to the given value.\n     * </p>\n     */\n    public JobExecutionException(String msg, Throwable cause,\n            boolean refireImmediately) {\n        super(msg, cause);\n\n        refire = refireImmediately;\n    }\n    \n    /**\n     * Create a JobExecutionException with the given message and the 're-fire \n     * immediately' flag set to the given value.\n     */\n    public JobExecutionException(String msg, boolean refireImmediately) {\n        super(msg);\n\n        refire = refireImmediately;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void setRefireImmediately(boolean refire) {\n        this.refire = refire;\n    }\n\n    public boolean refireImmediately() {\n        return refire;\n    }\n\n    public void setUnscheduleFiringTrigger(boolean unscheduleTrigg) {\n        this.unscheduleTrigg = unscheduleTrigg;\n    }\n\n    public boolean unscheduleFiringTrigger() {\n        return unscheduleTrigg;\n    }\n\n    public void setUnscheduleAllTriggers(boolean unscheduleAllTriggs) {\n        this.unscheduleAllTriggs = unscheduleAllTriggs;\n    }\n\n    public boolean unscheduleAllTriggers() {\n        return unscheduleAllTriggs;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobKey.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.utils.Key;\n\n/**\n * Uniquely identifies a {@link JobDetail}.\n * \n * <p>Keys are composed of both a name and group, and the name must be unique\n * within the group.  If only a name is specified then the default group\n * name will be used.</p> \n *\n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *  \n * \n * @see Job\n * @see Key#DEFAULT_GROUP\n */\npublic final class JobKey extends Key<JobKey> {\n\n    private static final long serialVersionUID = -6073883950062574010L;\n    \n    public JobKey(String name) {\n        super(name, null);\n    }\n\n    public JobKey(String name, String group) {\n        super(name, group);\n    }\n\n    public static JobKey jobKey(String name) {\n        return new JobKey(name, null);\n    }\n    \n    public static JobKey jobKey(String name, String group) {\n        return new JobKey(name, group);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobListener.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * The interface to be implemented by classes that want to be informed when a\n * <code>{@link org.quartz.JobDetail}</code> executes. In general,\n * applications that use a <code>Scheduler</code> will not have use for this\n * mechanism.\n * \n * @see ListenerManager#addJobListener(JobListener, Matcher)\n * @see Matcher\n * @see Job\n * @see JobExecutionContext\n * @see JobExecutionException\n * @see TriggerListener\n * \n * @author James House\n */\npublic interface JobListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name of the <code>JobListener</code>.\n     * </p>\n     */\n    String getName();\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * is about to be executed (an associated <code>{@link Trigger}</code>\n     * has occurred).\n     * </p>\n     * \n     * <p>\n     * This method will not be invoked if the execution of the Job was vetoed\n     * by a <code>{@link TriggerListener}</code>.\n     * </p>\n     * \n     * @see #jobExecutionVetoed(JobExecutionContext)\n     */\n    void jobToBeExecuted(JobExecutionContext context);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * was about to be executed (an associated <code>{@link Trigger}</code>\n     * has occurred), but a <code>{@link TriggerListener}</code> vetoed it's \n     * execution.\n     * </p>\n     * \n     * @see #jobToBeExecuted(JobExecutionContext)\n     */\n    void jobExecutionVetoed(JobExecutionContext context);\n\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> after a <code>{@link org.quartz.JobDetail}</code>\n     * has been executed, and be for the associated <code>Trigger</code>'s\n     * <code>triggered(xx)</code> method has been called.\n     * </p>\n     */\n    void jobWasExecuted(JobExecutionContext context,\n            JobExecutionException jobException);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/JobPersistenceException.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An exception that is thrown to indicate that there has been a failure in the\n * scheduler's underlying persistence mechanism.\n * \n * @author James House\n */\npublic class JobPersistenceException extends SchedulerException {\n  \n    private static final long serialVersionUID = -8924958757341995694L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>JobPersistenceException</code> with the given message.\n     * </p>\n     */\n    public JobPersistenceException(String msg) {\n        super(msg);\n    }\n\n\n    /**\n     * <p>\n     * Create a <code>JobPersistenceException</code> with the given message\n     * and cause.\n     * </p>\n     */\n    public JobPersistenceException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ListenerManager.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.List;\n\n/**\n * Client programs may be interested in the 'listener' interfaces that are\n * available from Quartz. The <code>{@link JobListener}</code> interface\n * provides notifications of <code>Job</code> executions. The \n * <code>{@link TriggerListener}</code> interface provides notifications of \n * <code>Trigger</code> firings. The <code>{@link SchedulerListener}</code> \n * interface provides notifications of <code>Scheduler</code> events and \n * errors.  Listeners can be associated with local schedulers through the \n * {@link ListenerManager} interface.  \n * \n * <p>Listener registration order is preserved, and hence notification of listeners\n * will be in the order in which they were registered.</p>\n * \n * @author jhouse\n * @since 2.0 - previously listeners were managed directly on the Scheduler interface.\n */\npublic interface ListenerManager {\n\n    /**\n     * Add the given <code>{@link JobListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for all Jobs.\n     * \n     * Because no matchers are provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addJobListener(JobListener jobListener);\n\n    /**\n     * Add the given <code>{@link JobListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Jobs that are matched by the\n     * given Matcher.\n     * \n     * If no matchers are provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addJobListener(JobListener jobListener, Matcher<JobKey> matcher);\n\n    /**\n     * Add the given <code>{@link JobListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Jobs that are matched by ANY of the\n     * given Matchers.\n     * \n     * If no matchers are provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addJobListener(JobListener jobListener, Matcher<JobKey>... matchers);\n\n    /**\n     * Add the given <code>{@link JobListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Jobs that are matched by ANY of the\n     * given Matchers.\n     * \n     * If no matchers are provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addJobListener(JobListener jobListener, List<Matcher<JobKey>> matchers);\n\n    /**\n     * Add the given Matcher to the set of matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matcher the additional matcher to apply for selecting events\n     * @return true if the identified listener was found and updated\n     */\n    boolean addJobListenerMatcher(String listenerName, Matcher<JobKey> matcher);\n\n    /**\n     * Remove the given Matcher to the set of matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matcher the additional matcher to apply for selecting events\n     * @return true if the given matcher was found and removed from the listener's list of matchers\n     */\n    boolean removeJobListenerMatcher(String listenerName, Matcher<JobKey> matcher);\n\n    /**\n     * Set the set of Matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     * \n     * <p>Removes any existing matchers for the identified listener!</p>\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matchers the matchers to apply for selecting events\n     * @return true if the given matcher was found and removed from the listener's list of matchers\n     */\n    boolean setJobListenerMatchers(String listenerName, List<Matcher<JobKey>> matchers);\n\n    /**\n     * Get the set of Matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     * \n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @return the matchers registered for selecting events for the identified listener\n     */\n    List<Matcher<JobKey>> getJobListenerMatchers(String listenerName);\n\n    /**\n     * Remove the identified <code>{@link JobListener}</code> from the <code>Scheduler</code>.\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    boolean removeJobListener(String name);\n\n    /**\n     * Get a List containing all of the <code>{@link JobListener}</code>s in\n     * the <code>Scheduler</code>, in the order in which they were registered.\n     */\n    List<JobListener> getJobListeners();\n\n    /**\n     * Get the <code>{@link JobListener}</code> that has the given name.\n     */\n    JobListener getJobListener(String name);\n\n    /**\n     * Add the given <code>{@link TriggerListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for all Triggers.\n     * \n     * Because no matcher is provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addTriggerListener(TriggerListener triggerListener);\n    \n    /**\n     * Add the given <code>{@link TriggerListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Triggers that are matched by the\n     * given Matcher.\n     * \n     * If no matcher is provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> matcher);\n    \n    /**\n     * Add the given <code>{@link TriggerListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Triggers that are matched by ANY of the\n     * given Matchers.\n     * \n     * If no matcher is provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey>... matchers);\n\n    /**\n     * Add the given <code>{@link TriggerListener}</code> to the <code>Scheduler</code>,\n     * and register it to receive events for Triggers that are matched by ANY of the\n     * given Matchers.\n     * \n     * If no matcher is provided, the <code>EverythingMatcher</code> will be used.\n     * \n     * @see Matcher\n     * @see org.quartz.impl.matchers.EverythingMatcher\n     */\n    void addTriggerListener(TriggerListener triggerListener, List<Matcher<TriggerKey>> matchers);\n\n    /**\n     * Add the given Matcher to the set of matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matcher the additional matcher to apply for selecting events\n     * @return true if the identified listener was found and updated\n     */\n    boolean addTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher);\n\n    /**\n     * Remove the given Matcher to the set of matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matcher the additional matcher to apply for selecting events\n     * @return true if the given matcher was found and removed from the listener's list of matchers\n     */\n    boolean removeTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher);\n\n    /**\n     * Set the set of Matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     * \n     * <p>Removes any existing matchers for the identified listener!</p>\n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @param matchers the matchers to apply for selecting events\n     * @return true if the given matcher was found and removed from the listener's list of matchers\n     */\n    boolean setTriggerListenerMatchers(String listenerName, List<Matcher<TriggerKey>> matchers);\n\n    /**\n     * Get the set of Matchers for which the listener\n     * will receive events if ANY of the matchers match.\n     * \n     *  \n     * @param listenerName the name of the listener to add the matcher to\n     * @return the matchers registered for selecting events for the identified listener\n     */\n    List<Matcher<TriggerKey>> getTriggerListenerMatchers(String listenerName);\n\n    /**\n     * Remove the identified <code>{@link TriggerListener}</code> from the <code>Scheduler</code>.\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    boolean removeTriggerListener(String name);\n\n    /**\n     * Get a List containing all of the <code>{@link TriggerListener}</code>s \n     * in the <code>Scheduler</code>, in the order in which they were registered.\n     */\n    List<TriggerListener> getTriggerListeners();\n\n    /**\n     * Get the <code>{@link TriggerListener}</code> that has the given name.\n     */\n    TriggerListener getTriggerListener(String name);\n\n    /**\n     * Register the given <code>{@link SchedulerListener}</code> with the\n     * <code>Scheduler</code>.\n     */\n    void addSchedulerListener(SchedulerListener schedulerListener);\n\n    /**\n     * Remove the given <code>{@link SchedulerListener}</code> from the\n     * <code>Scheduler</code>.\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    boolean removeSchedulerListener(SchedulerListener schedulerListener);\n\n    /**\n     * Get a List containing all of the <code>{@link SchedulerListener}</code>s\n     * registered with the <code>Scheduler</code>, in the order in which they were registered.\n     */\n    List<SchedulerListener> getSchedulerListeners();\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/Matcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\n\nimport org.quartz.utils.Key;\n\n/**\n * Matchers can be used in various {@link Scheduler} API methods to \n * select the entities that should be operated upon.\n *  \n * @author jhouse\n * @since 2.0\n */\npublic interface Matcher<T extends Key<?>> extends Serializable {\n\n    boolean isMatch(T key);\n \n    int hashCode();\n\n    boolean equals(Object obj);\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ObjectAlreadyExistsException.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An exception that is thrown to indicate that an attempt to store a new\n * object (i.e. <code>{@link org.quartz.JobDetail}</code>,<code>{@link Trigger}</code>\n * or <code>{@link Calendar}</code>) in a <code>{@link Scheduler}</code>\n * failed, because one with the same name and group already exists.\n * \n * @author James House\n */\npublic class ObjectAlreadyExistsException extends JobPersistenceException {\n  \n    private static final long serialVersionUID = -558301282071659896L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>ObjectAlreadyExistsException</code> with the given\n     * message.\n     * </p>\n     */\n    public ObjectAlreadyExistsException(String msg) {\n        super(msg);\n    }\n\n    /**\n     * <p>\n     * Create a <code>ObjectAlreadyExistsException</code> and auto-generate a\n     * message using the name/group from the given <code>JobDetail</code>.\n     * </p>\n     * \n     * <p>\n     * The message will read: <BR>\"Unable to store Job with name: '__' and\n     * group: '__', because one already exists with this identification.\"\n     * </p>\n     */\n    public ObjectAlreadyExistsException(JobDetail offendingJob) {\n        super(\"Unable to store Job : '\" + offendingJob.getKey()\n                + \"', because one already exists with this identification.\");\n    }\n\n    /**\n     * <p>\n     * Create a <code>ObjectAlreadyExistsException</code> and auto-generate a\n     * message using the name/group from the given <code>Trigger</code>.\n     * </p>\n     * \n     * <p>\n     * The message will read: <BR>\"Unable to store Trigger with name: '__' and\n     * group: '__', because one already exists with this identification.\"\n     * </p>\n     */\n    public ObjectAlreadyExistsException(Trigger offendingTrigger) {\n        super(\"Unable to store Trigger with name: '\"\n                + offendingTrigger.getKey().getName() + \"' and group: '\"\n                + offendingTrigger.getKey().getGroup()\n                + \"', because one already exists with this identification.\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/PersistJobDataAfterExecution.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that marks a {@link Job} class as one that makes updates to its\n * {@link JobDataMap} during execution, and wishes the scheduler to re-store the\n * <code>JobDataMap</code> when execution completes. \n *   \n * <p>Jobs that are marked with this annotation should also seriously consider\n * using the {@link DisallowConcurrentExecution} annotation, to avoid data\n * storage race conditions with concurrently executing job instances.</p>\n *\n * @see DisallowConcurrentExecution\n * \n * @author jhouse\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface PersistJobDataAfterExecution {\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ScheduleBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.spi.MutableTrigger;\n\npublic abstract class ScheduleBuilder<T extends Trigger>  {\n    \n    protected abstract MutableTrigger build();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/Scheduler.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.JobFactory;\nimport org.quartz.utils.Key;\n\n/**\n * This is the main interface of a Quartz Scheduler.\n * \n * <p>\n * A <code>Scheduler</code> maintains a registry of <code>{@link org.quartz.JobDetail}</code>s\n * and <code>{@link Trigger}</code>s. Once registered, the <code>Scheduler</code>\n * is responsible for executing <code>Job</code> s when their associated\n * <code>Trigger</code> s fire (when their scheduled time arrives).\n * </p>\n * \n * <p>\n * <code>Scheduler</code> instances are produced by a <code>{@link SchedulerFactory}</code>.\n * A scheduler that has already been created/initialized can be found and used\n * through the same factory that produced it. After a <code>Scheduler</code>\n * has been created, it is in \"stand-by\" mode, and must have its \n * <code>start()</code> method called before it will fire any <code>Job</code>s.\n * </p>\n * \n * <p>\n * <code>Job</code> s are to be created by the 'client program', by defining\n * a class that implements the <code>{@link org.quartz.Job}</code>\n * interface. <code>{@link JobDetail}</code> objects are then created (also\n * by the client) to define a individual instances of the <code>Job</code>.\n * <code>JobDetail</code> instances can then be registered with the <code>Scheduler</code>\n * via the <code>scheduleJob(JobDetail, Trigger)</code> or <code>addJob(JobDetail, boolean)</code>\n * method.\n * </p>\n * \n * <p>\n * <code>Trigger</code> s can then be defined to fire individual <code>Job</code>\n * instances based on given schedules. <code>SimpleTrigger</code> s are most\n * useful for one-time firings, or firing at an exact moment in time, with N\n * repeats with a given delay between them. <code>CronTrigger</code> s allow\n * scheduling based on time of day, day of week, day of month, and month of\n * year.\n * </p>\n * \n * <p>\n * <code>Job</code> s and <code>Trigger</code> s have a name and group\n * associated with them, which should uniquely identify them within a single\n * <code>{@link Scheduler}</code>. The 'group' feature may be useful for\n * creating logical groupings or categorizations of <code>Jobs</code> s and\n * <code>Triggers</code>s. If you don't have need for assigning a group to a\n * given <code>Jobs</code> of <code>Triggers</code>, then you can use the\n * <code>DEFAULT_GROUP</code> constant defined on this interface.\n * </p>\n * \n * <p>\n * Stored <code>Job</code> s can also be 'manually' triggered through the use\n * of the <code>triggerJob(String jobName, String jobGroup)</code> function.\n * </p>\n * \n * <p>\n * Client programs may also be interested in the 'listener' interfaces that are\n * available from Quartz. The <code>{@link JobListener}</code> interface\n * provides notifications of <code>Job</code> executions. The <code>{@link TriggerListener}</code>\n * interface provides notifications of <code>Trigger</code> firings. The\n * <code>{@link SchedulerListener}</code> interface provides notifications of\n * <code>Scheduler</code> events and errors.  Listeners can be associated with\n * local schedulers through the {@link ListenerManager} interface.  \n * </p>\n * \n * <p>\n * The setup/configuration of a <code>Scheduler</code> instance is very\n * customizable. Please consult the documentation distributed with Quartz.\n * </p>\n * \n * @see Job\n * @see JobDetail\n * @see JobBuilder\n * @see Trigger\n * @see TriggerBuilder\n * @see JobListener\n * @see TriggerListener\n * @see SchedulerListener\n * \n * @author James House\n * @author Sharada Jambula\n */\npublic interface Scheduler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * A (possibly) useful constant that can be used for specifying the group\n     * that <code>Job</code> and <code>Trigger</code> instances belong to.\n     */\n    String DEFAULT_GROUP = Key.DEFAULT_GROUP;\n\n    /**\n     * A constant <code>Trigger</code> group name used internally by the\n     * scheduler - clients should not use the value of this constant\n     * (\"RECOVERING_JOBS\") for the name of a <code>Trigger</code>'s group.\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String DEFAULT_RECOVERY_GROUP = \"RECOVERING_JOBS\";\n\n    /**\n     * A constant <code>Trigger</code> group name used internally by the\n     * scheduler - clients should not use the value of this constant\n     * (\"FAILED_OVER_JOBS\") for the name of a <code>Trigger</code>'s group.\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String DEFAULT_FAIL_OVER_GROUP = \"FAILED_OVER_JOBS\";\n\n\n    /**\n     * A constant <code>JobDataMap</code> key that can be used to retrieve the\n     * name of the original <code>Trigger</code> from a recovery trigger's\n     * data map in the case of a job recovering after a failed scheduler\n     * instance.\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String FAILED_JOB_ORIGINAL_TRIGGER_NAME =  \"QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME\";\n\n    /**\n     * A constant <code>JobDataMap</code> key that can be used to retrieve the\n     * group of the original <code>Trigger</code> from a recovery trigger's\n     * data map in the case of a job recovering after a failed scheduler\n     * instance.\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String FAILED_JOB_ORIGINAL_TRIGGER_GROUP =  \"QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP\";\n\n    /**\n     * A constant <code>JobDataMap</code> key that can be used to retrieve the\n     * fire time of the original <code>Trigger</code> from a recovery\n     * trigger's data map in the case of a job recovering after a failed scheduler\n     * instance.  \n     * \n     * <p>Note that this is the time the original firing actually occurred,\n     * which may be different from the scheduled fire time - as a trigger doesn't\n     * always fire exactly on time.</p>\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS =  \"QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING\";\n\n    /**\n     * A constant <code>JobDataMap</code> key that can be used to retrieve the\n     * scheduled fire time of the original <code>Trigger</code> from a recovery\n     * trigger's data map in the case of a job recovering after a failed scheduler\n     * instance.  \n     * \n     * <p>Note that this is the time the original firing was scheduled for,\n     * which may be different from the actual firing time - as a trigger doesn't\n     * always fire exactly on time.</p>\n     *\n     * @see org.quartz.JobDetail#requestsRecovery()\n     */\n    String FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS =  \"QRTZ_FAILED_JOB_ORIG_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS_AS_STRING\";\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Returns the name of the <code>Scheduler</code>.\n     */\n    String getSchedulerName() throws SchedulerException;\n\n    /**\n     * Returns the instance Id of the <code>Scheduler</code>.\n     */\n    String getSchedulerInstanceId() throws SchedulerException;\n\n    /**\n     * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.\n     */\n    SchedulerContext getContext() throws SchedulerException;\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduler State Management Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n    \n    /**\n     * Starts the <code>Scheduler</code>'s threads that fire <code>{@link Trigger}s</code>.\n     * When a scheduler is first created it is in \"stand-by\" mode, and will not\n     * fire triggers.  The scheduler can also be put into stand-by mode by\n     * calling the <code>standby()</code> method. \n     * \n     * <p>\n     * The misfire/recovery process will be started, if it is the initial call\n     * to this method on this scheduler instance.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if <code>shutdown()</code> has been called, or there is an\n     *           error within the <code>Scheduler</code>.\n     *\n     * @see #startDelayed(int)\n     * @see #standby()\n     * @see #shutdown()\n     */\n    void start() throws SchedulerException;\n\n    /**\n     * Calls {#start()} after the indicated number of seconds.\n     * (This call does not block). This can be useful within applications that\n     * have initializers that create the scheduler immediately, before the\n     * resources needed by the executing jobs have been fully initialized.\n     *\n     * @throws SchedulerException\n     *           if <code>shutdown()</code> has been called, or there is an\n     *           error within the <code>Scheduler</code>.\n     *\n     * @see #start() \n     * @see #standby()\n     * @see #shutdown()\n     */\n    void startDelayed(int seconds) throws SchedulerException;\n\n    /**\n     * Whether the scheduler has been started.  \n     * \n     * <p>\n     * Note: This only reflects whether <code>{@link #start()}</code> has ever\n     * been called on this Scheduler, so it will return <code>true</code> even \n     * if the <code>Scheduler</code> is currently in standby mode or has been \n     * since shutdown.\n     * </p>\n     * \n     * @see #start()\n     * @see #isShutdown()\n     * @see #isInStandbyMode()\n     */    \n    boolean isStarted() throws SchedulerException;\n    \n    /**\n     * Temporarily halts the <code>Scheduler</code>'s firing of <code>{@link Trigger}s</code>.\n     * \n     * <p>\n     * When <code>start()</code> is called (to bring the scheduler out of \n     * stand-by mode), trigger misfire instructions will NOT be applied\n     * during the execution of the <code>start()</code> method - any misfires \n     * will be detected immediately afterward (by the <code>JobStore</code>'s \n     * normal process).\n     * </p>\n     * \n     * <p>\n     * The scheduler is not destroyed, and can be re-started at any time.\n     * </p>\n     * \n     * @see #start()\n     * @see #pauseAll()\n     */\n    void standby() throws SchedulerException;\n\n    /**\n     * Reports whether the <code>Scheduler</code> is in stand-by mode.\n     * \n     * @see #standby()\n     * @see #start()\n     */\n    boolean isInStandbyMode() throws SchedulerException;\n\n    /**\n     * Halts the <code>Scheduler</code>'s firing of <code>{@link Trigger}s</code>,\n     * and cleans up all resources associated with the Scheduler. Equivalent to\n     * <code>shutdown(false)</code>.\n     * \n     * <p>\n     * The scheduler cannot be re-started.\n     * </p>\n     * \n     * @see #shutdown(boolean)\n     */\n    void shutdown() throws SchedulerException;\n\n    /**\n     * Halts the <code>Scheduler</code>'s firing of <code>{@link Trigger}s</code>,\n     * and cleans up all resources associated with the Scheduler.\n     * \n     * <p>\n     * The scheduler cannot be re-started.\n     * </p>\n     * \n     * @param waitForJobsToComplete\n     *          if <code>true</code> the scheduler will not allow this method\n     *          to return until all currently executing jobs have completed.\n     * \n     * @see #shutdown\n     */\n    void shutdown(boolean waitForJobsToComplete)\n        throws SchedulerException;\n\n    /**\n     * Reports whether the <code>Scheduler</code> has been shutdown.\n     */\n    boolean isShutdown() throws SchedulerException;\n\n    /**\n     * Get a <code>SchedulerMetaData</code> object describing the settings\n     * and capabilities of the scheduler instance.\n     * \n     * <p>\n     * Note that the data returned is an 'instantaneous' snap-shot, and that as\n     * soon as it's returned, the meta data values may be different.\n     * </p>\n     */\n    SchedulerMetaData getMetaData() throws SchedulerException;\n\n    /**\n     * Return a list of <code>JobExecutionContext</code> objects that\n     * represent all currently executing Jobs in this Scheduler instance.\n     * \n     * <p>\n     * This method is not cluster aware.  That is, it will only return Jobs\n     * currently executing in this Scheduler instance, not across the entire\n     * cluster.\n     * </p>\n     * \n     * <p>\n     * Note that the list returned is an 'instantaneous' snap-shot, and that as\n     * soon as it's returned, the true list of executing jobs may be different.\n     * Also please read the doc associated with <code>JobExecutionContext</code>-\n     * especially if you're using RMI.\n     * </p>\n     * \n     * @see JobExecutionContext\n     */\n    List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException;\n\n    /**\n     * Set the <code>JobFactory</code> that will be responsible for producing \n     * instances of <code>Job</code> classes.\n     * \n     * <p>\n     * JobFactories may be of use to those wishing to have their application\n     * produce <code>Job</code> instances via some special mechanism, such as to\n     * give the opportunity for dependency injection.\n     * </p>\n     * \n     * @see org.quartz.spi.JobFactory\n     */\n    void setJobFactory(JobFactory factory) throws SchedulerException;\n    \n    \n    /**\n     * Get a reference to the scheduler's <code>ListenerManager</code>,\n     * through which listeners may be registered.\n     *  \n     * @return the scheduler's <code>ListenerManager</code>\n     * @throws SchedulerException if the scheduler is not local\n     * @see ListenerManager\n     * @see JobListener\n     * @see TriggerListener\n     * @see SchedulerListener\n     */\n    ListenerManager getListenerManager()  throws SchedulerException;\n    \n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduling-related Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Add the given <code>{@link org.quartz.JobDetail}</code> to the\n     * Scheduler, and associate the given <code>{@link Trigger}</code> with\n     * it.\n     * \n     * <p>\n     * If the given Trigger does not reference any <code>Job</code>, then it\n     * will be set to reference the Job passed with it into this method.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if the Job or Trigger cannot be added to the Scheduler, or\n     *           there is an internal Scheduler error.\n     */\n    Date scheduleJob(JobDetail jobDetail, Trigger trigger)\n        throws SchedulerException;\n\n    /**\n     * Schedule the given <code>{@link org.quartz.Trigger}</code> with the\n     * <code>Job</code> identified by the <code>Trigger</code>'s settings.\n     * \n     * @throws SchedulerException\n     *           if the indicated Job does not exist, or the Trigger cannot be\n     *           added to the Scheduler, or there is an internal Scheduler\n     *           error.\n     */\n    Date scheduleJob(Trigger trigger) throws SchedulerException;\n\n    /**\n     * Schedule all of the given jobs with the related set of triggers.\n     * \n     * <p>If any of the given jobs or triggers already exist (or more\n     * specifically, if the keys are not unique) and the replace \n     * parameter is not set to true then an exception will be thrown.</p>\n     * \n     * @throws ObjectAlreadyExistsException if the job/trigger keys\n     * are not unique and the replace flag is not set to true. \n     */\n    void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException;\n    \n    /**\n     * Schedule the given job with the related set of triggers.\n     * \n     * <p>If any of the given job or triggers already exist (or more\n     * specifically, if the keys are not unique) and the replace \n     * parameter is not set to true then an exception will be thrown.</p>\n     * \n     * @throws ObjectAlreadyExistsException if the job/trigger keys\n     * are not unique and the replace flag is not set to true. \n     */\n    void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException;\n    \n    /**\n     * Remove the indicated <code>{@link Trigger}</code> from the scheduler.\n     * \n     * <p>If the related job does not have any other triggers, and the job is\n     * not durable, then the job will also be deleted.</p>\n     */\n    boolean unscheduleJob(TriggerKey triggerKey)\n        throws SchedulerException;\n\n    /**\n     * Remove all of the indicated <code>{@link Trigger}</code>s from the scheduler.\n     * \n     * <p>If the related job does not have any other triggers, and the job is\n     * not durable, then the job will also be deleted.</p>\n     * \n     * <p>Note that while this bulk operation is likely more efficient than\n     * invoking <code>unscheduleJob(TriggerKey triggerKey)</code> several\n     * times, it may have the adverse affect of holding data locks for a\n     * single long duration of time (rather than lots of small durations\n     * of time).</p> \n     */\n    boolean unscheduleJobs(List<TriggerKey> triggerKeys)\n        throws SchedulerException;\n    \n    /**\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given key, and store the new given one - which must be associated\n     * with the same job (the new trigger must have the job name and group specified)\n     * - however, the new trigger need not have the same name as the old trigger.\n     * \n     * @param triggerKey identity of the trigger to replace\n     * @param newTrigger\n     *          The new <code>Trigger</code> to be stored.\n     * \n     * @return <code>null</code> if a <code>Trigger</code> with the given\n     *         name and group was not found and removed from the store (and the\n     *         new trigger is therefore not stored), otherwise\n     *         the first fire time of the newly scheduled trigger is returned.\n     */\n    Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) \n        throws SchedulerException;\n    \n    /**\n     * Add the given <code>Job</code> to the Scheduler - with no associated\n     * <code>Trigger</code>. The <code>Job</code> will be 'dormant' until\n     * it is scheduled with a <code>Trigger</code>, or <code>Scheduler.triggerJob()</code>\n     * is called for it.\n     * \n     * <p>\n     * The <code>Job</code> must by definition be 'durable', if it is not,\n     * SchedulerException will be thrown.\n     * </p>\n     *\n     * @see #addJob(JobDetail, boolean, boolean)\n     *\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or if the Job is not\n     *           durable, or a Job with the same name already exists, and\n     *           <code>replace</code> is <code>false</code>.\n     */\n    void addJob(JobDetail jobDetail, boolean replace)\n        throws SchedulerException;\n\n    /**\n     * Add the given <code>Job</code> to the Scheduler - with no associated\n     * <code>Trigger</code>. The <code>Job</code> will be 'dormant' until\n     * it is scheduled with a <code>Trigger</code>, or <code>Scheduler.triggerJob()</code>\n     * is called for it.\n     *\n     * <p>\n     * With the <code>storeNonDurableWhileAwaitingScheduling</code> parameter\n     * set to <code>true</code>, a non-durable job can be stored.  Once it is\n     * scheduled, it will resume normal non-durable behavior (i.e. be deleted\n     * once there are no remaining associated triggers).\n     * </p>\n     *\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or if the Job is not\n     *           durable, or a Job with the same name already exists, and\n     *           <code>replace</code> is <code>false</code>.\n     */\n    void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)\n            throws SchedulerException;\n\n    /**\n     * Delete the identified <code>Job</code> from the Scheduler - and any\n     * associated <code>Trigger</code>s.\n     * \n     * @return true if the Job was found and deleted.\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error.\n     */\n    boolean deleteJob(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Delete the identified <code>Job</code>s from the Scheduler - and any\n     * associated <code>Trigger</code>s.\n     * \n     * <p>Note that while this bulk operation is likely more efficient than\n     * invoking <code>deleteJob(JobKey jobKey)</code> several\n     * times, it may have the adverse affect of holding data locks for a\n     * single long duration of time (rather than lots of small durations\n     * of time).</p>\n     *  \n     * @return true if all of the Jobs were found and deleted, false if \n     * one or more were not deleted.\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error.\n     */\n    boolean deleteJobs(List<JobKey> jobKeys)\n        throws SchedulerException;\n    \n    /**\n     * Trigger the identified <code>{@link org.quartz.JobDetail}</code>\n     * (execute it now).\n     */\n    void triggerJob(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Trigger the identified <code>{@link org.quartz.JobDetail}</code>\n     * (execute it now).\n     * \n     * @param data the (possibly <code>null</code>) JobDataMap to be \n     * associated with the trigger that fires the job immediately. \n     */\n    void triggerJob(JobKey jobKey, JobDataMap data)\n        throws SchedulerException;\n\n    /**\n     * Pause the <code>{@link org.quartz.JobDetail}</code> with the given\n     * key - by pausing all of its current <code>Trigger</code>s.\n     * \n     * @see #resumeJob(JobKey)\n     */\n    void pauseJob(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the\n     * matching groups - by pausing all of their <code>Trigger</code>s.\n     *\n     * <p>\n     * The Scheduler will \"remember\" the groups paused, and impose the\n     * pause on any new jobs that are added to any of those groups\n     * until it is resumed.\n     * </p>\n     * \n     * <p>NOTE: There is a limitation that only exactly matched groups\n     * can be remembered as paused.  For example, if there are preexisting\n     * job in groups \"aaa\" and \"bbb\" and a matcher is given to pause\n     * groups that start with \"a\" then the group \"aaa\" will be remembered\n     * as paused and any subsequently added jobs in group \"aaa\" will be paused,\n     * however if a job is added to group \"axx\" it will not be paused,\n     * as \"axx\" wasn't known at the time the \"group starts with a\" matcher \n     * was applied.  HOWEVER, if there are preexisting groups \"aaa\" and\n     * \"bbb\" and a matcher is given to pause the group \"axx\" (with a\n     * group equals matcher) then no jobs will be paused, but it will be \n     * remembered that group \"axx\" is paused and later when a job is added \n     * in that group, it will become paused.</p>\n     *\n     * @param matcher The matcher to evaluate against know groups\n     * @throws SchedulerException On error\n     * @see #resumeJobs(org.quartz.impl.matchers.GroupMatcher)\n     */\n    void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;\n\n    /**\n     * Pause the <code>{@link Trigger}</code> with the given key.\n     * \n     * @see #resumeTrigger(TriggerKey)\n     */\n    void pauseTrigger(TriggerKey triggerKey)\n        throws SchedulerException;\n\n    /**\n     * Pause all of the <code>{@link Trigger}s</code> in the groups matching.\n     * \n     * <p>\n     * The Scheduler will \"remember\" all the groups paused, and impose the\n     * pause on any new triggers that are added to any of those groups\n     * until it is resumed.\n     * </p>\n     * \n     * <p>NOTE: There is a limitation that only exactly matched groups\n     * can be remembered as paused.  For example, if there are preexisting\n     * triggers in groups \"aaa\" and \"bbb\" and a matcher is given to pause\n     * groups that start with \"a\" then the group \"aaa\" will be remembered as\n     * paused and any subsequently added triggers in that group be paused,\n     * however if a trigger is added to group \"axx\" it will not be paused,\n     * as \"axx\" wasn't known at the time the \"group starts with a\" matcher \n     * was applied.  HOWEVER, if there are preexisting groups \"aaa\" and\n     * \"bbb\" and a matcher is given to pause the group \"axx\" (with a\n     * group equals matcher) then no triggers will be paused, but it will be \n     * remembered that group \"axx\" is paused and later when a trigger is added\n     * in that group, it will become paused.</p>\n     * \n     * @param matcher The matcher to evaluate against know groups\n     * @throws SchedulerException\n     * @see #resumeTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;\n\n    /**\n     * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with\n     * the given key.\n     * \n     * <p>\n     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one\n     * or more fire-times, then the <code>Trigger</code>'s misfire\n     * instruction will be applied.\n     * </p>\n     * \n     * @see #pauseJob(JobKey)\n     */\n    void resumeJob(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>\n     * in matching groups.\n     * \n     * <p>\n     * If any of the <code>Job</code> s had <code>Trigger</code> s that\n     * missed one or more fire-times, then the <code>Trigger</code>'s\n     * misfire instruction will be applied.\n     * </p>\n     * \n     * @param matcher The matcher to evaluate against known paused groups\n     * @throws SchedulerException On error\n     * @see #pauseJobs(GroupMatcher)\n     */\n    void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;\n\n    /**\n     * Resume (un-pause) the <code>{@link Trigger}</code> with the given\n     * key.\n     * \n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseTrigger(TriggerKey)\n     */\n    void resumeTrigger(TriggerKey triggerKey)\n        throws SchedulerException;\n\n    /**\n     * Resume (un-pause) all of the <code>{@link Trigger}s</code> in matching groups.\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @param matcher The matcher to evaluate against know paused groups\n     * @throws SchedulerException On error\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;\n\n    /**\n     * Pause all triggers - similar to calling <code>pauseTriggerGroup(group)</code>\n     * on every group, however, after using this method <code>resumeAll()</code> \n     * must be called to clear the scheduler's state of 'remembering' that all \n     * new triggers will be paused as they are added. \n     * \n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     * \n     * @see #resumeAll()\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     * @see #standby()\n     */\n    void pauseAll() throws SchedulerException;\n\n    /**\n     * Resume (un-pause) all triggers - similar to calling \n     * <code>resumeTriggerGroup(group)</code> on every group.\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseAll()\n     */\n    void resumeAll() throws SchedulerException;\n\n    /**\n     * Get the names of all known <code>{@link org.quartz.JobDetail}</code>\n     * groups.\n     */\n    List<String> getJobGroupNames() throws SchedulerException;\n\n    /**\n     * Get the keys of all the <code>{@link org.quartz.JobDetail}s</code>\n     * in the matching groups.\n     * @param matcher Matcher to evaluate against known groups\n     * @return Set of all keys matching\n     * @throws SchedulerException On error\n     */\n    Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException;\n\n    /**\n     * Get all <code>{@link Trigger}</code> s that are associated with the\n     * identified <code>{@link org.quartz.JobDetail}</code>.\n     * \n     * <p>The returned Trigger objects will be snap-shots of the actual stored\n     * triggers.  If you wish to modify a trigger, you must re-store the\n     * trigger afterward (e.g. see {@link #rescheduleJob(TriggerKey, Trigger)}).\n     * </p>\n     * \n     */\n    List<? extends Trigger> getTriggersOfJob(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Get the names of all known <code>{@link Trigger}</code> groups.\n     */\n    List<String> getTriggerGroupNames() throws SchedulerException;\n\n    /**\n     * Get the names of all the <code>{@link Trigger}s</code> in the given\n     * group.\n     * @param matcher Matcher to evaluate against known groups\n     * @return List of all keys matching\n     * @throws SchedulerException On error\n     */\n    Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException;\n\n    /**\n     * Get the names of all <code>{@link Trigger}</code> groups that are paused.\n     */\n    Set<String> getPausedTriggerGroups() throws SchedulerException;\n    \n    /**\n     * Get the <code>{@link JobDetail}</code> for the <code>Job</code>\n     * instance with the given key.\n     * \n     * <p>The returned JobDetail object will be a snap-shot of the actual stored\n     * JobDetail.  If you wish to modify the JobDetail, you must re-store the\n     * JobDetail afterward (e.g. see {@link #addJob(JobDetail, boolean)}).\n     * </p>\n     * \n     */\n    JobDetail getJobDetail(JobKey jobKey)\n        throws SchedulerException;\n\n    /**\n     * Gets all the {@link org.quartz.JobDetail Jobdetails}\n     * in the matching groups.\n     *\n     * <p>The returned JobDetail objects will be a snap-shot of the actual stored\n     * JobDetail.  If you wish to modify the JobDetail, you must re-store the\n     * JobDetail afterward (e.g. see {@link #addJob(JobDetail, boolean)}).\n     * </p>\n     * @param matcher Matcher to evaluate against known groups\n     * @return List of all JobDetail matching\n     * @throws SchedulerException On error\n     */\n    List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws SchedulerException;\n\n    /**\n     * Get the <code>{@link Trigger}</code> instance with the given key.\n     * \n     * <p>The returned Trigger object will be a snap-shot of the actual stored\n     * trigger.  If you wish to modify the trigger, you must re-store the\n     * trigger afterward (e.g. see {@link #rescheduleJob(TriggerKey, Trigger)}).\n     * </p>\n     */\n    Trigger getTrigger(TriggerKey triggerKey)\n        throws SchedulerException;\n\n    /**\n     * Get the current state of the identified <code>{@link Trigger}</code>.\n     * \n     * @see Trigger.TriggerState\n     */\n    TriggerState getTriggerState(TriggerKey triggerKey)\n        throws SchedulerException;\n\n    /**\n     * Reset the current state of the identified <code>{@link Trigger}</code>\n     * from {@link TriggerState#ERROR} to {@link TriggerState#NORMAL} or\n     * {@link TriggerState#PAUSED} as appropriate.\n     *\n     * <p>Only affects triggers that are in ERROR state - if identified trigger is not\n     * in that state then the result is a no-op.</p>\n     *\n     * <p>The result will be the trigger returning to the normal, waiting to\n     * be fired state, unless the trigger's group has been paused, in which\n     * case it will go into the PAUSED state.</p>\n     *\n     * @see Trigger.TriggerState\n     */\n    void resetTriggerFromErrorState(TriggerKey triggerKey)\n        throws SchedulerException;\n    /**\n     * Add (register) the given <code>Calendar</code> to the Scheduler.\n     * \n     * @param updateTriggers whether or not to update existing triggers that\n     * referenced the already existing calendar so that they are 'correct'\n     * based on the new trigger. \n     * \n     *  \n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or a Calendar with\n     *           the same name already exists, and <code>replace</code> is\n     *           <code>false</code>.\n     */\n    void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)\n        throws SchedulerException;\n\n    /**\n     * Delete the identified <code>Calendar</code> from the Scheduler.\n     * \n     * <p>\n     * If removal of the <code>Calendar</code> would result in\n     * <code>Trigger</code>s pointing to nonexistent calendars, then a\n     * <code>SchedulerException</code> will be thrown.\n     * </p>\n     * \n     * @return true if the Calendar was found and deleted.\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or one or more \n     *           triggers reference the calendar\n     */\n    boolean deleteCalendar(String calName) throws SchedulerException;\n\n    /**\n     * Get the <code>{@link Calendar}</code> instance with the given name.\n     */\n    Calendar getCalendar(String calName) throws SchedulerException;\n\n    /**\n     * Get the names of all registered <code>{@link Calendar}s</code>.\n     */\n    List<String> getCalendarNames() throws SchedulerException;\n\n    /**\n     * Request the interruption, within this Scheduler instance, of all \n     * currently executing instances of the identified <code>Job</code>, which \n     * must be an implementor of the <code>InterruptableJob</code> interface.\n     * \n     * <p>\n     * If more than one instance of the identified job is currently executing,\n     * the <code>InterruptableJob#interrupt()</code> method will be called on\n     * each instance.  However, there is a limitation that in the case that  \n     * <code>interrupt()</code> on one instances throws an exception, all \n     * remaining  instances (that have not yet been interrupted) will not have \n     * their <code>interrupt()</code> method called.\n     * </p>\n     * \n     * <p>\n     * This method is not cluster aware.  That is, it will only interrupt \n     * instances of the identified InterruptableJob currently executing in this \n     * Scheduler instance, not across the entire cluster.\n     * </p>\n     * \n     * @return true if at least one instance of the identified job was found\n     * and interrupted.\n     * @throws UnableToInterruptJobException if the job does not implement\n     * <code>InterruptableJob</code>, or there is an exception while \n     * interrupting the job.\n     * @see InterruptableJob#interrupt()\n     * @see #getCurrentlyExecutingJobs()\n     * @see #interrupt(String)\n     */\n    boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException;\n    \n    /**\n     * Request the interruption, within this Scheduler instance, of the \n     * identified executing <code>Job</code> instance, which \n     * must be an implementor of the <code>InterruptableJob</code> interface.\n     * \n     * <p>\n     * This method is not cluster aware.  That is, it will only interrupt \n     * instances of the identified InterruptableJob currently executing in this \n     * Scheduler instance, not across the entire cluster.\n     * </p>\n     * \n     * @param fireInstanceId the unique identifier of the job instance to\n     * be interrupted (see {@link JobExecutionContext#getFireInstanceId()}\n     * @return true if the identified job instance was found and interrupted.\n     * @throws UnableToInterruptJobException if the job does not implement\n     * <code>InterruptableJob</code>, or there is an exception while \n     * interrupting the job.\n     * @see InterruptableJob#interrupt()\n     * @see #getCurrentlyExecutingJobs()\n     * @see JobExecutionContext#getFireInstanceId()\n     * @see #interrupt(JobKey)\n     */\n    boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException;\n    \n    /**\n     * Determine whether a {@link Job} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param jobKey the identifier to check for\n     * @return true if a Job exists with the given identifier\n     * @throws SchedulerException \n     */\n    boolean checkExists(JobKey jobKey) throws SchedulerException; \n   \n    /**\n     * Determine whether a {@link Trigger} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param triggerKey the identifier to check for\n     * @return true if a Trigger exists with the given identifier\n     * @throws SchedulerException \n     */\n    boolean checkExists(TriggerKey triggerKey) throws SchedulerException;\n    \n    /**\n     * Clears (deletes!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws SchedulerException\n     */\n    void clear() throws SchedulerException;\n\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerConfigException.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An exception that is thrown to indicate that there is a misconfiguration of\n * the <code>SchedulerFactory</code>- or one of the components it\n * configures.\n * \n * @author James House\n */\npublic class SchedulerConfigException extends SchedulerException {\n  \n    private static final long serialVersionUID = -5921239824646083098L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>JobPersistenceException</code> with the given message.\n     * </p>\n     */\n    public SchedulerConfigException(String msg) {\n        super(msg);\n    }\n\n    /**\n     * <p>\n     * Create a <code>JobPersistenceException</code> with the given message\n     * and cause.\n     * </p>\n     */\n    public SchedulerConfigException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerContext.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\nimport org.quartz.utils.StringKeyDirtyFlagMap;\n\n/**\n * Holds context/environment data that can be made available to Jobs as they\n * are executed. This feature is much like the ServletContext feature when\n * working with J2EE servlets.\n * \n * <p>\n * Future versions of Quartz may make distinctions on how it propagates\n * data in <code>SchedulerContext</code> between instances of proxies to a \n * single scheduler instance - i.e. if Quartz is being used via RMI.\n * </p>\n *  \n * @see Scheduler#getContext\n * \n * @author James House\n */\npublic class SchedulerContext extends StringKeyDirtyFlagMap implements Serializable {\n  \n    private static final long serialVersionUID = -6659641334616491764L;\n  \n    /**\n     * Create an empty <code>SchedulerContext</code>.\n     */\n    public SchedulerContext() {\n        super(15);\n    }\n\n    /**\n     * Create a <code>SchedulerContext</code> with the given data.\n     */\n    public SchedulerContext(Map<?, ?> map) {\n        this();\n        @SuppressWarnings(\"unchecked\") // param must be a String key map.\n        Map<String, ?> mapTyped = (Map<String, ?>)map;\n        putAll(mapTyped);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerException.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n\n\n/**\n * Base class for exceptions thrown by the Quartz <code>{@link Scheduler}</code>.\n * \n * <p>\n * <code>SchedulerException</code>s may contain a reference to another\n * <code>Exception</code>, which was the underlying cause of the <code>SchedulerException</code>.\n * </p>\n * \n * @author James House\n */\npublic class SchedulerException extends Exception {\n  \n    private static final long serialVersionUID = 174841398690789156L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public SchedulerException() {\n        super();\n    }\n\n    public SchedulerException(String msg) {\n        super(msg);\n    }\n\n    public SchedulerException(Throwable cause) {\n        super(cause);\n    }\n\n    public SchedulerException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n\n\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Return the exception that is the underlying cause of this exception.\n     * </p>\n     * \n     * <p>\n     * This may be used to find more detail about the cause of the error.\n     * </p>\n     * \n     * @return the underlying exception, or <code>null</code> if there is not\n     *         one.\n     */\n    public Throwable getUnderlyingException() {\n        return super.getCause();\n    }\n\n    @Override\n    public String toString() {\n        Throwable cause = getUnderlyingException(); \n        if (cause == null || cause == this) {\n            return super.toString();\n        } else {\n            return super.toString() + \" [See nested exception: \" + cause + \"]\";\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerFactory.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Collection;\n\n/**\n * Provides a mechanism for obtaining client-usable handles to <code>Scheduler</code>\n * instances.\n * \n * @see Scheduler\n * @see org.quartz.impl.StdSchedulerFactory\n * \n * @author James House\n */\npublic interface SchedulerFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Returns a client-usable handle to a <code>Scheduler</code>.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if there is a problem with the underlying <code>Scheduler</code>.\n     */\n    Scheduler getScheduler() throws SchedulerException;\n\n    /**\n     * <p>\n     * Returns a handle to the Scheduler with the given name, if it exists.\n     * </p>\n     */\n    Scheduler getScheduler(String schedName) throws SchedulerException;\n\n    /**\n     * <p>\n     * Returns handles to all known Schedulers (made by any SchedulerFactory\n     * within this jvm.).\n     * </p>\n     */\n    Collection<Scheduler> getAllSchedulers() throws SchedulerException;\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerListener.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * The interface to be implemented by classes that want to be informed of major\n * <code>{@link Scheduler}</code> events.\n * \n * @see Scheduler\n * @see JobListener\n * @see TriggerListener\n * \n * @author James House\n */\npublic interface SchedulerListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * is scheduled.\n     * </p>\n     */\n    void jobScheduled(Trigger trigger);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * is unscheduled.\n     * </p>\n     * \n     * @see SchedulerListener#schedulingDataCleared()\n     */\n    void jobUnscheduled(TriggerKey triggerKey);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has reached the condition in which it will never fire again.\n     * </p>\n     */\n    void triggerFinalized(Trigger trigger);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has been paused.\n     * </p>\n     */\n    void triggerPaused(TriggerKey triggerKey);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a \n     * group of <code>{@link Trigger}s</code> has been paused.\n     * </p>\n     * \n     * <p>If all groups were paused then triggerGroup will be null</p>\n     * \n     * @param triggerGroup the paused group, or null if all were paused\n     */\n    void triggersPaused(String triggerGroup);\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has been un-paused.\n     * </p>\n     */\n    void triggerResumed(TriggerKey triggerKey);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a \n     * group of <code>{@link Trigger}s</code> has been un-paused.\n     * </p>\n     */\n    void triggersResumed(String triggerGroup);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * has been added.\n     * </p>\n     */\n    void jobAdded(JobDetail jobDetail);\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * has been deleted.\n     * </p>\n     */\n    void jobDeleted(JobKey jobKey);\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * has been paused.\n     * </p>\n     */\n    void jobPaused(JobKey jobKey);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a \n     * group of <code>{@link org.quartz.JobDetail}s</code> has been paused.\n     * </p>\n     * \n     * @param jobGroup the paused group, or null if all were paused\n     */\n    void jobsPaused(String jobGroup);\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>\n     * has been un-paused.\n     * </p>\n     */\n    void jobResumed(JobKey jobKey);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a \n     * group of <code>{@link org.quartz.JobDetail}s</code> has been un-paused.\n     * </p>\n     */\n    void jobsResumed(String jobGroup);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a serious error has\n     * occurred within the scheduler - such as repeated failures in the <code>JobStore</code>,\n     * or the inability to instantiate a <code>Job</code> instance when its\n     * <code>Trigger</code> has fired.\n     * </p>\n     * \n     * <p>\n     * The <code>getErrorCode()</code> method of the given SchedulerException\n     * can be used to determine more specific information about the type of\n     * error that was encountered.\n     * </p>\n     */\n    void schedulerError(String msg, SchedulerException cause);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it has move to standby mode.\n     * </p>\n     */\n    void schedulerInStandbyMode();\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it has started.\n     * </p>\n     */\n    void schedulerStarted();\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it is starting.\n     * </p>\n     */\n    void schedulerStarting();\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it has shutdown.\n     * </p>\n     */\n    void schedulerShutdown();\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it has begun the shutdown sequence.\n     * </p>\n     */\n    void schedulerShuttingdown();\n\n    /**\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that all jobs, triggers and calendars were deleted.\n     */\n    void schedulingDataCleared();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SchedulerMetaData.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Date;\n\n/**\n * Describes the settings and capabilities of a given <code>{@link Scheduler}</code>\n * instance.\n * \n * @author James House\n */\npublic class SchedulerMetaData implements java.io.Serializable {\n  \n    private static final long serialVersionUID = 4203690002633917647L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final String schedName;\n\n    private final String schedInst;\n\n    private final Class<?> schedClass;\n\n    private final boolean isRemote;\n\n    private final boolean started;\n\n    private final boolean isInStandbyMode;\n\n    private final boolean shutdown;\n\n    private final Date startTime;\n\n    private final int numJobsExec;\n\n    private final Class<?> jsClass;\n\n    private final boolean jsPersistent;\n\n    private final boolean jsClustered;\n\n    private final Class<?> tpClass;\n\n    private final int tpSize;\n\n    private final String version;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public SchedulerMetaData(String schedName, String schedInst,\n            Class<?> schedClass, boolean isRemote, boolean started,\n            boolean isInStandbyMode, boolean shutdown, Date startTime, int numJobsExec,\n            Class<?> jsClass, boolean jsPersistent, boolean jsClustered, Class<?> tpClass, int tpSize,\n            String version) {\n        this.schedName = schedName;\n        this.schedInst = schedInst;\n        this.schedClass = schedClass;\n        this.isRemote = isRemote;\n        this.started = started;\n        this.isInStandbyMode = isInStandbyMode;\n        this.shutdown = shutdown;\n        this.startTime = startTime;\n        this.numJobsExec = numJobsExec;\n        this.jsClass = jsClass;\n        this.jsPersistent = jsPersistent;\n        this.jsClustered = jsClustered;\n        this.tpClass = tpClass;\n        this.tpSize = tpSize;\n        this.version = version;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Returns the name of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerName() {\n        return schedName;\n    }\n\n    /**\n     * <p>\n     * Returns the instance Id of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerInstanceId() {\n        return schedInst;\n    }\n\n    /**\n     * <p>\n     * Returns the class-name of the <code>Scheduler</code> instance.\n     * </p>\n     */\n    public Class<?> getSchedulerClass() {\n        return schedClass;\n    }\n\n    /**\n     * <p>\n     * Returns the <code>Date</code> at which the Scheduler started running.\n     * </p>\n     * \n     * @return null if the scheduler has not been started.\n     */\n    public Date getRunningSince() {\n        return startTime;\n    }\n    \n    /**\n     * <p>\n     * Returns the number of jobs executed since the <code>Scheduler</code>\n     * started..\n     * </p>\n     */\n    public int getNumberOfJobsExecuted() {\n        return numJobsExec;\n    }\n\n    /**\n     * <p>\n     * Returns whether the <code>Scheduler</code> is being used remotely (via\n     * RMI).\n     * </p>\n     */\n    public boolean isSchedulerRemote() {\n        return isRemote;\n    }\n\n    /**\n     * <p>\n     * Returns whether the scheduler has been started.\n     * </p>\n     * \n     * <p>\n     * Note: <code>isStarted()</code> may return <code>true</code> even if\n     * <code>isInStandbyMode()</code> returns <code>true</code>.\n     * </p>\n     */\n    public boolean isStarted() {\n        return started;\n    }\n\n    /**\n     * Reports whether the <code>Scheduler</code> is in standby mode.\n     */\n    public boolean isInStandbyMode() {\n        return isInStandbyMode;\n    }\n\n    /**\n     * <p>\n     * Reports whether the <code>Scheduler</code> has been shutdown.\n     * </p>\n     */\n    public boolean isShutdown() {\n        return shutdown;\n    }\n\n    /**\n     * <p>\n     * Returns the class-name of the <code>JobStore</code> instance that is\n     * being used by the <code>Scheduler</code>.\n     * </p>\n     */\n    public Class<?> getJobStoreClass() {\n        return jsClass;\n    }\n    \n    /**\n     * <p>\n     * Returns whether or not the <code>Scheduler</code>'s<code>JobStore</code>\n     * instance supports persistence.\n     * </p>\n     */\n    public boolean isJobStoreSupportsPersistence() {\n        return jsPersistent;\n    }\n\n    /**\n     * <p>\n     * Returns whether or not the <code>Scheduler</code>'s<code>JobStore</code>\n     * is clustered.\n     * </p>\n     */\n    public boolean isJobStoreClustered() {\n        return jsClustered;\n    }\n\n    /**\n     * <p>\n     * Returns the class-name of the <code>ThreadPool</code> instance that is\n     * being used by the <code>Scheduler</code>.\n     * </p>\n     */\n    public Class<?> getThreadPoolClass() {\n        return tpClass;\n    }\n\n    /**\n     * <p>\n     * Returns the number of threads currently in the <code>Scheduler</code>'s\n     * <code>ThreadPool</code>.\n     * </p>\n     */\n    public int getThreadPoolSize() {\n        return tpSize;\n    }\n\n    /**\n     * <p>\n     * Returns the version of Quartz that is running.\n     * </p>\n     */\n    public String getVersion() {\n        return version;\n    }\n\n    /**\n     * <p>\n     * Return a simple string representation of this object.\n     * </p>\n     */\n    @Override\n    public String toString() {\n        try {\n            return getSummary();\n        } catch (SchedulerException se) {\n            return \"SchedulerMetaData: undeterminable.\";\n        }\n    }\n\n    /**\n     * <p>\n     * Returns a formatted (human readable) String describing all the <code>Scheduler</code>'s\n     * meta-data values.\n     * </p>\n     * \n     * <p>\n     * The format of the String looks something like this:\n     * </p>\n     * <pre>\n     *  Quartz Scheduler 'SchedulerName' with instanceId 'SchedulerInstanceId' Scheduler class: 'org.quartz.impl.StdScheduler' - running locally. Running since: '11:33am on Jul 19, 2002' Not currently paused. Number of Triggers fired: '123' Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with '8' threads Using job-store 'org.quartz.impl.JDBCJobStore' - which supports persistence.\n     * </pre>\n     */\n    public String getSummary() throws SchedulerException {\n        StringBuilder str = new StringBuilder(\"Quartz Scheduler (v\");\n        str.append(getVersion());\n        str.append(\") '\");\n\n        str.append(getSchedulerName());\n        str.append(\"' with instanceId '\");\n        str.append(getSchedulerInstanceId());\n        str.append(\"'\\n\");\n\n        str.append(\"  Scheduler class: '\");\n        str.append(getSchedulerClass().getName());\n        str.append(\"'\");\n        if (isSchedulerRemote()) {\n            str.append(\" - access via RMI.\");\n        } else {\n            str.append(\" - running locally.\");\n        }\n        str.append(\"\\n\");\n\n        if (!isShutdown()) {\n            if (getRunningSince() != null) {\n                str.append(\"  Running since: \");\n                str.append(getRunningSince());\n            } else {\n                str.append(\"  NOT STARTED.\");\n            }\n            str.append(\"\\n\");\n\n            if (isInStandbyMode()) {\n                str.append(\"  Currently in standby mode.\");\n            } else {\n                str.append(\"  Not currently in standby mode.\");\n            }\n        } else {\n            str.append(\"  Scheduler has been SHUTDOWN.\");\n        }\n        str.append(\"\\n\");\n\n        str.append(\"  Number of jobs executed: \");\n        str.append(getNumberOfJobsExecuted());\n        str.append(\"\\n\");\n\n        str.append(\"  Using thread pool '\");\n        str.append(getThreadPoolClass().getName());\n        str.append(\"' - with \");\n        str.append(getThreadPoolSize());\n        str.append(\" threads.\");\n        str.append(\"\\n\");\n\n        str.append(\"  Using job-store '\");\n        str.append(getJobStoreClass().getName());\n        str.append(\"' - which \");\n        if (isJobStoreSupportsPersistence()) {\n            str.append(\"supports persistence.\");\n        } else {\n            str.append(\"does not support persistence.\");\n        }\n        if (isJobStoreClustered()) {\n            str.append(\" and is clustered.\");\n        } else {\n            str.append(\" and is not clustered.\");\n        }\n        str.append(\"\\n\");\n\n        return str.toString();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SimpleScheduleBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\n\n/**\n * <code>SimpleScheduleBuilder</code> is a {@link ScheduleBuilder} \n * that defines strict/literal interval-based schedules for \n * <code>Trigger</code>s.\n *  \n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *\n * @see SimpleTrigger\n * @see CalendarIntervalScheduleBuilder\n * @see CronScheduleBuilder\n * @see ScheduleBuilder\n * @see TriggerBuilder\n */\npublic class SimpleScheduleBuilder extends ScheduleBuilder<SimpleTrigger> {\n\n    private long interval = 0;\n    private int repeatCount = 0;\n    private int misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_SMART_POLICY;\n    \n    protected SimpleScheduleBuilder() {\n    }\n    \n    /**\n     * Create a SimpleScheduleBuilder.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder simpleSchedule() {\n        return new SimpleScheduleBuilder();\n    }\n    \n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with a 1 minute interval.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatMinutelyForever() {\n\n        return simpleSchedule()\n            .withIntervalInMinutes(1)\n            .repeatForever();\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with an interval\n     * of the given number of minutes.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatMinutelyForever(int minutes) {\n\n        return simpleSchedule()\n            .withIntervalInMinutes(minutes)\n            .repeatForever();\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with a 1 second interval.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatSecondlyForever() {\n\n        return simpleSchedule()\n            .withIntervalInSeconds(1)\n            .repeatForever();\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with an interval\n     * of the given number of seconds.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatSecondlyForever(int seconds) {\n\n        return simpleSchedule()\n            .withIntervalInSeconds(seconds)\n            .repeatForever();\n    }\n    \n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with a 1 hour interval.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatHourlyForever() {\n\n        return simpleSchedule()\n            .withIntervalInHours(1)\n            .repeatForever();\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat forever with an interval\n     * of the given number of hours.\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatHourlyForever(int hours) {\n\n        return simpleSchedule()\n            .withIntervalInHours(hours)\n            .repeatForever();\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with a 1 minute interval.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInMinutes(1)\n            .withRepeatCount(count - 1);\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with an interval of the given number of minutes.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count, int minutes) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInMinutes(minutes)\n            .withRepeatCount(count - 1);\n    }\n    \n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with a 1 second interval.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInSeconds(1)\n            .withRepeatCount(count - 1);\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with an interval of the given number of seconds.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count, int seconds) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInSeconds(seconds)\n            .withRepeatCount(count - 1);\n    }\n    \n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with a 1 hour interval.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInHours(1)\n            .withRepeatCount(count - 1);\n    }\n\n    /**\n     * Create a SimpleScheduleBuilder set to repeat the given number\n     * of times - 1  with an interval of the given number of hours.\n     * \n     * <p>Note: Total count = 1 (at start time) + repeat count</p>\n     * \n     * @return the new SimpleScheduleBuilder\n     */\n    public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count, int hours) {\n        if(count < 1)\n            throw new IllegalArgumentException(\"Total count of firings must be at least one! Given count: \" + count);\n\n        return simpleSchedule()\n            .withIntervalInHours(hours)\n            .withRepeatCount(count - 1);\n    }\n    \n    /**\n     * Build the actual Trigger -- NOT intended to be invoked by end users,\n     * but will rather be invoked by a TriggerBuilder which this \n     * ScheduleBuilder is given to.\n     * \n     * @see TriggerBuilder#withSchedule(ScheduleBuilder)\n     */\n    @Override\n    public MutableTrigger build() {\n\n        SimpleTriggerImpl st = new SimpleTriggerImpl();\n        st.setRepeatInterval(interval);\n        st.setRepeatCount(repeatCount);\n        st.setMisfireInstruction(misfireInstruction);\n        \n        return st;\n    }\n\n    /**\n     * Specify a repeat interval in milliseconds. \n     * \n     * @param intervalInMillis the number of seconds at which the trigger should repeat.\n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatInterval()\n     * @see #withRepeatCount(int)\n     */\n    public SimpleScheduleBuilder withIntervalInMilliseconds(long intervalInMillis) {\n        this.interval = intervalInMillis;\n        return this;\n    }\n    \n    /**\n     * Specify a repeat interval in seconds - which will then be multiplied\n     * by 1000 to produce milliseconds. \n     * \n     * @param intervalInSeconds the number of seconds at which the trigger should repeat.\n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatInterval()\n     * @see #withRepeatCount(int)\n     */\n    public SimpleScheduleBuilder withIntervalInSeconds(int intervalInSeconds) {\n        this.interval = intervalInSeconds * 1000L;\n        return this;\n    }\n    \n    /**\n     * Specify a repeat interval in minutes - which will then be multiplied\n     * by 60 * 1000 to produce milliseconds. \n     * \n     * @param intervalInMinutes the number of seconds at which the trigger should repeat.\n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatInterval()\n     * @see #withRepeatCount(int)\n     */\n    public SimpleScheduleBuilder withIntervalInMinutes(int intervalInMinutes) {\n        this.interval = intervalInMinutes * DateBuilder.MILLISECONDS_IN_MINUTE;\n        return this;\n    }\n\n    /**\n     * Specify a repeat interval in minutes - which will then be multiplied\n     * by 60 * 60 * 1000 to produce milliseconds. \n     * \n     * @param intervalInHours the number of seconds at which the trigger should repeat.\n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatInterval()\n     * @see #withRepeatCount(int)\n     */\n    public SimpleScheduleBuilder withIntervalInHours(int intervalInHours) {\n        this.interval = intervalInHours * DateBuilder.MILLISECONDS_IN_HOUR;\n        return this;\n    }\n    \n    /**\n     * Specify the number of times the trigger will repeat - the total number of\n     * firings will be this number + 1. \n     * \n     * @param triggerRepeatCount the number of times the trigger should repeat after the initial firing.\n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatCount()\n     * @see #repeatForever()\n     */\n    public SimpleScheduleBuilder withRepeatCount(int triggerRepeatCount) {\n        this.repeatCount = triggerRepeatCount;\n        return this;\n    }\n    \n    /**\n     * Specify that the trigger will repeat indefinitely. \n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#getRepeatCount()\n     * @see SimpleTrigger#REPEAT_INDEFINITELY\n     * @see #withIntervalInMilliseconds(long)\n     * @see #withIntervalInSeconds(int)\n     * @see #withIntervalInMinutes(int)\n     * @see #withIntervalInHours(int)\n     */\n    public SimpleScheduleBuilder repeatForever() {\n        this.repeatCount = SimpleTrigger.REPEAT_INDEFINITELY;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see Trigger#MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY\n     */\n    public SimpleScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {\n        misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link SimpleTrigger#MISFIRE_INSTRUCTION_FIRE_NOW} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#MISFIRE_INSTRUCTION_FIRE_NOW\n     */\n    \n    public SimpleScheduleBuilder withMisfireHandlingInstructionFireNow() {\n        misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT\n     */\n    public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithExistingCount() {\n        misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT;\n        return this;\n    }\n    \n    /**\n     * If the Trigger misfires, use the \n     * {@link SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT\n     */\n    public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithRemainingCount() {\n        misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;\n        return this;\n    }\n\n    /**\n     * If the Trigger misfires, use the \n     * {@link SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT\n     */\n    public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithExistingCount() {\n        misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;\n        return this;\n    }\n    \n    /**\n     * If the Trigger misfires, use the \n     * {@link SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT} instruction.\n     * \n     * @return the updated SimpleScheduleBuilder\n     * @see SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT\n     */\n    public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithRemainingCount() {\n        misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/SimpleTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * A <code>{@link Trigger}</code> that is used to fire a <code>Job</code>\n * at a given moment in time, and optionally repeated at a specified interval.\n * \n * @see TriggerBuilder\n * @see SimpleScheduleBuilder\n * \n * @author James House\n * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium.\n */\npublic interface SimpleTrigger extends Trigger {\n\n    long serialVersionUID = -3735980074222850397L;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link SimpleTrigger}</code> wants to be fired\n     * now by <code>Scheduler</code>.\n     * </p>\n     * \n     * <p>\n     * <i>NOTE:</i> This instruction should typically only be used for\n     * 'one-shot' (non-repeating) Triggers. If it is used on a trigger with a\n     * repeat count &gt; 0 then it is equivalent to the instruction <code>{@link #MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT}\n     * </code>.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_FIRE_NOW = 1;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link SimpleTrigger}</code> wants to be\n     * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code>\n     * excludes 'now') with the repeat count left as-is.  This does obey the\n     * <code>Trigger</code> end-time however, so if 'now' is after the\n     * end-time the <code>Trigger</code> will not fire again.\n     * </p>\n     * \n     * <p>\n     * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget'\n     * the start-time and repeat-count that it was originally setup with (this\n     * is only an issue if you for some reason wanted to be able to tell what\n     * the original values were at some later time).\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link SimpleTrigger}</code> wants to be\n     * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code>\n     * excludes 'now') with the repeat count set to what it would be, if it had\n     * not missed any firings.  This does obey the <code>Trigger</code> end-time \n     * however, so if 'now' is after the end-time the <code>Trigger</code> will \n     * not fire again.\n     * </p>\n     * \n     * <p>\n     * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget'\n     * the start-time and repeat-count that it was originally setup with.\n     * Instead, the repeat count on the trigger will be changed to whatever\n     * the remaining repeat count is (this is only an issue if you for some\n     * reason wanted to be able to tell what the original values were at some\n     * later time).\n     * </p>\n     * \n     * <p>\n     * <i>NOTE:</i> This instruction could cause the <code>Trigger</code>\n     * to go to the 'COMPLETE' state after firing 'now', if all the\n     * repeat-fire-times where missed.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link SimpleTrigger}</code> wants to be\n     * re-scheduled to the next scheduled time after 'now' - taking into\n     * account any associated <code>{@link Calendar}</code>, and with the\n     * repeat count set to what it would be, if it had not missed any firings.\n     * </p>\n     * \n     * <p>\n     * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code>\n     * to go directly to the 'COMPLETE' state if all fire-times where missed.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4;\n    \n    /**\n     * <p>\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>{@link SimpleTrigger}</code> wants to be\n     * re-scheduled to the next scheduled time after 'now' - taking into\n     * account any associated <code>{@link Calendar}</code>, and with the\n     * repeat count left unchanged.\n     * </p>\n     * \n     * <p>\n     * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code>\n     * to go directly to the 'COMPLETE' state if the end-time of the trigger\n     * has arrived.\n     * </p>\n     */\n    int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5;\n    \n    /**\n     * <p>\n     * Used to indicate the 'repeat count' of the trigger is indefinite. Or in\n     * other words, the trigger should repeat continually until the trigger's\n     * ending timestamp.\n     * </p>\n     */\n    int REPEAT_INDEFINITELY = -1;\n\n    /**\n     * Get the number of times the <code>SimpleTrigger</code> should\n     * repeat, after the initial firing, after which it will be automatically deleted.\n     *\n     * The total number of firings will be this number + 1.\n     *\n     * @return the number of times the trigger should repeat after the initial firing.\n     * @see #REPEAT_INDEFINITELY\n     */\n    int getRepeatCount();\n\n    /**\n     * <p>\n     * Get the time interval (in milliseconds) at which the <code>SimpleTrigger</code> should repeat.\n     * </p>\n     */\n    long getRepeatInterval();\n    \n    /**\n     * <p>\n     * Get the number of times the <code>SimpleTrigger</code> has already fired.\n     * </p>\n     */\n    int getTimesTriggered();\n\n    TriggerBuilder<SimpleTrigger> getTriggerBuilder();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/StatefulJob.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * A marker interface for <code>{@link org.quartz.JobDetail}</code> s that\n * wish to have their state maintained between executions.\n * \n * <p>\n * <code>StatefulJob</code> instances follow slightly different rules from\n * regular <code>Job</code> instances. The key difference is that their\n * associated <code>{@link JobDataMap}</code> is re-persisted after every\n * execution of the job, thus preserving state for the next execution. The\n * other difference is that stateful jobs are not allowed to execute\n * concurrently, which means new triggers that occur before the completion of\n * the <code>execute(xx)</code> method will be delayed.\n * </p>\n * \n * @see DisallowConcurrentExecution\n * @see PersistJobDataAfterExecution\n * \n * @see Job\n * @see JobDetail\n * @see JobDataMap\n * @see Scheduler\n * \n *\n * @deprecated use DisallowConcurrentExecution and/or PersistJobDataAfterExecution annotations instead.\n * \n * @author James House\n */\n@Deprecated\n@PersistJobDataAfterExecution\n@DisallowConcurrentExecution\npublic interface StatefulJob extends Job {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/TimeOfDay.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz;\n\nimport java.io.Serializable;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.TimeZone;\n\n/**\n * Represents a time in hour, minute and second of any given day.\n * \n * <p>The hour is in 24-hour convention, meaning values are from 0 to 23.</p> \n * \n * @see DailyTimeIntervalScheduleBuilder\n * \n * @since 2.0.3\n * \n * @author James House\n * @author Zemian Deng &lt;saltnlight5@gmail.com&gt;\n */\npublic class TimeOfDay implements Serializable {\n\n    private static final long serialVersionUID = 2964774315889061771L;\n\n    private final int hour;\n    private final int minute;\n    private final int second;\n    \n    /**\n     * Create a TimeOfDay instance for the given hour, minute and second.\n     * \n     * @param hour The hour of day, between 0 and 23.\n     * @param minute The minute of the hour, between 0 and 59.\n     * @param second The second of the minute, between 0 and 59.\n     * @throws IllegalArgumentException if one or more of the input values is out of their valid range.\n     */\n    public TimeOfDay(int hour, int minute, int second) {\n        this.hour = hour;\n        this.minute = minute;\n        this.second = second;\n        validate();\n    }\n    \n    /**\n     * Create a TimeOfDay instance for the given hour and minute (at the zero second of the minute).\n     * \n     * @param hour The hour of day, between 0 and 23.\n     * @param minute The minute of the hour, between 0 and 59.\n     * @throws IllegalArgumentException if one or more of the input values is out of their valid range.\n     */\n    public TimeOfDay(int hour, int minute) {\n        this.hour = hour;\n        this.minute = minute;\n        this.second = 0;\n        validate();\n    }\n    \n    private void validate() {\n        if(hour < 0 || hour > 23)\n            throw new IllegalArgumentException(\"Hour must be from 0 to 23\");\n        if(minute < 0 || minute > 59)\n            throw new IllegalArgumentException(\"Minute must be from 0 to 59\");\n        if(second < 0 || second > 59)\n            throw new IllegalArgumentException(\"Second must be from 0 to 59\");\n    }\n\n    /**\n     * Create a TimeOfDay instance for the given hour, minute and second.\n     * \n     * @param hour The hour of day, between 0 and 23.\n     * @param minute The minute of the hour, between 0 and 59.\n     * @param second The second of the minute, between 0 and 59.\n     * @throws IllegalArgumentException if one or more of the input values is out of their valid range.\n     */\n    public static TimeOfDay hourMinuteAndSecondOfDay(int hour, int minute, int second) {\n        return new TimeOfDay(hour, minute, second);\n    }\n\n    /**\n     * Create a TimeOfDay instance for the given hour and minute (at the zero second of the minute).\n     * \n     * @param hour The hour of day, between 0 and 23.\n     * @param minute The minute of the hour, between 0 and 59.\n     * @throws IllegalArgumentException if one or more of the input values is out of their valid range.\n     */\n    public static TimeOfDay hourAndMinuteOfDay(int hour, int minute) {\n        return new TimeOfDay(hour, minute);\n    }\n    \n    /**\n     * The hour of the day (between 0 and 23).\n     * \n     * @return The hour of the day (between 0 and 23).\n     */\n    public int getHour() {\n        return hour;\n    }\n\n    /**\n     * The minute of the hour.\n     * \n     * @return The minute of the hour (between 0 and 59).\n     */\n    public int getMinute() {\n        return minute;\n    }\n\n    /**\n     * The second of the minute.\n     * \n     * @return The second of the minute (between 0 and 59).\n     */\n    public int getSecond() {\n        return second;\n    }\n\n    /**\n     * Determine with this time of day is before the given time of day.\n     * \n     * @return true this time of day is before the given time of day.\n     */\n    public boolean before(TimeOfDay timeOfDay) {\n        \n        if(timeOfDay.hour > hour)\n            return true;\n        if(timeOfDay.hour < hour)\n            return false;\n\n        if(timeOfDay.minute > minute)\n            return true;\n        if(timeOfDay.minute < minute)\n            return false;\n\n        if(timeOfDay.second > second)\n            return true;\n        if(timeOfDay.second < second)\n            return false;\n        \n        return false; // must be equal...\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if(!(obj instanceof TimeOfDay))\n            return false;\n        \n        TimeOfDay other = (TimeOfDay)obj;\n        \n        return (other.hour == hour && other.minute == minute && other.second == second);\n    }\n\n    @Override\n    public int hashCode() {\n        return (hour + 1) ^ (minute + 1) ^ (second + 1);\n    }\n    \n    /** Return a date with time of day reset to this object values. The millisecond value will be zero. */\n    public Date getTimeOfDayForDate(Date dateTime) {\n        if (dateTime == null)\n            return null;\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(dateTime);\n        cal.set(Calendar.HOUR_OF_DAY, hour);\n        cal.set(Calendar.MINUTE, minute);\n        cal.set(Calendar.SECOND, second);\n        cal.clear(Calendar.MILLISECOND);\n        return cal.getTime();\n    }\n    \n    /**\n     * Create a TimeOfDay from the given date, in the system default TimeZone.\n     * \n     * @param dateTime The java.util.Date from which to extract Hour, Minute and Second.\n     */\n    public static TimeOfDay hourAndMinuteAndSecondFromDate(Date dateTime) {\n        return hourAndMinuteAndSecondFromDate(dateTime, null);\n    }\n    \n    /**\n     * Create a TimeOfDay from the given date, in the given TimeZone.\n     * \n     * @param dateTime The java.util.Date from which to extract Hour, Minute and Second.\n     * @param tz The TimeZone from which relate Hour, Minute and Second for the given date.  If null, system default\n     * TimeZone will be used.\n     */\n    public static TimeOfDay hourAndMinuteAndSecondFromDate(Date dateTime, TimeZone tz) {\n        if (dateTime == null)\n            return null;\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(dateTime);\n        if(tz != null)\n            cal.setTimeZone(tz);\n        \n        return new TimeOfDay(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));\n    }\n    \n    /**\n     * Create a TimeOfDay from the given date (at the zero-second), in the system default TimeZone.\n     * \n     * @param dateTime The java.util.Date from which to extract Hour and Minute.\n     */\n    public static TimeOfDay hourAndMinuteFromDate(Date dateTime) {\n        return hourAndMinuteFromDate(dateTime, null);\n    }\n    \n    /**\n     * Create a TimeOfDay from the given date (at the zero-second), in the system default TimeZone.\n     * \n     * @param dateTime The java.util.Date from which to extract Hour and Minute.\n     * @param tz The TimeZone from which relate Hour and Minute for the given date.  If null, system default\n     * TimeZone will be used.\n     */\n    public static TimeOfDay hourAndMinuteFromDate(Date dateTime, TimeZone tz) {\n        if (dateTime == null)\n            return null;\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(dateTime);\n        if(tz != null)\n            cal.setTimeZone(tz);\n        \n        return new TimeOfDay(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));\n    }\n    \n    @Override\n    public String toString() {\n        return \"TimeOfDay[\" + hour + \":\" + minute + \":\" + second + \"]\";\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/Trigger.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.io.Serializable;\nimport java.util.Comparator;\nimport java.util.Date;\n\n\n\n/**\n * The base interface with properties common to all <code>Trigger</code>s -\n * use {@link TriggerBuilder} to instantiate an actual Trigger.\n * \n * <p>\n * <code>Triggers</code>s have a {@link TriggerKey} associated with them, which\n * should uniquely identify them within a single <code>{@link Scheduler}</code>.\n * </p>\n * \n * <p>\n * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code>s\n * are scheduled. Many <code>Trigger</code>s can point to the same <code>Job</code>,\n * but a single <code>Trigger</code> can only point to one <code>Job</code>.\n * </p>\n * \n * <p>\n * Triggers can 'send' parameters/data to <code>Job</code>s by placing contents\n * into the <code>JobDataMap</code> on the <code>Trigger</code>.\n * </p>\n *\n * @see TriggerBuilder\n * @see JobDataMap\n * @see JobExecutionContext\n * @see TriggerUtils\n * @see SimpleTrigger\n * @see CronTrigger\n * @see CalendarIntervalTrigger\n * \n * @author James House\n */\npublic interface Trigger extends Serializable, Cloneable, Comparable<Trigger> {\n\n    long serialVersionUID = -3904243490805975570L;\n    \n    enum TriggerState { NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED }\n    \n    /**\n     * <p><code>NOOP</code> Instructs the <code>{@link Scheduler}</code> that the \n     * <code>{@link Trigger}</code> has no further instructions.</p>\n     * \n     * <p><code>RE_EXECUTE_JOB</code> Instructs the <code>{@link Scheduler}</code> that the \n     * <code>{@link Trigger}</code> wants the <code>{@link org.quartz.JobDetail}</code> to \n     * re-execute immediately. If not in a 'RECOVERING' or 'FAILED_OVER' situation, the\n     * execution context will be re-used (giving the <code>Job</code> the\n     * ability to 'see' anything placed in the context by its last execution).</p>\n     * \n     * <p><code>SET_TRIGGER_COMPLETE</code> Instructs the <code>{@link Scheduler}</code> that the \n     * <code>{@link Trigger}</code> should be put in the <code>COMPLETE</code> state.</p>\n     * \n     * <p><code>DELETE_TRIGGER</code> Instructs the <code>{@link Scheduler}</code> that the \n     * <code>{@link Trigger}</code> wants itself deleted.</p>\n     * \n     * <p><code>SET_ALL_JOB_TRIGGERS_COMPLETE</code> Instructs the <code>{@link Scheduler}</code> \n     * that all <code>Trigger</code>s referencing the same <code>{@link org.quartz.JobDetail}</code> \n     * as this one should be put in the <code>COMPLETE</code> state.</p>\n     * \n     * <p><code>SET_TRIGGER_ERROR</code> Instructs the <code>{@link Scheduler}</code> that all \n     * <code>Trigger</code>s referencing the same <code>{@link org.quartz.JobDetail}</code> as\n     * this one should be put in the <code>ERROR</code> state.</p>\n     *\n     * <p><code>SET_ALL_JOB_TRIGGERS_ERROR</code> Instructs the <code>{@link Scheduler}</code> that \n     * the <code>Trigger</code> should be put in the <code>ERROR</code> state.</p>\n     */\n    enum CompletedExecutionInstruction { NOOP, RE_EXECUTE_JOB, SET_TRIGGER_COMPLETE, DELETE_TRIGGER,\n        SET_ALL_JOB_TRIGGERS_COMPLETE, SET_TRIGGER_ERROR, SET_ALL_JOB_TRIGGERS_ERROR }\n\n    /**\n     * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire\n     * situation, the <code>updateAfterMisfire()</code> method will be called\n     * on the <code>Trigger</code> to determine the mis-fire instruction,\n     * which logic will be trigger-implementation-dependent.\n     * \n     * <p>\n     * In order to see if this instruction fits your needs, you should look at\n     * the documentation for the <code>updateAfterMisfire()</code> method\n     * on the particular <code>Trigger</code> implementation you are using.\n     * </p>\n     *\n     * @see org.quartz.impl.triggers.SimpleTriggerImpl#updateAfterMisfire(Calendar)\n     * @see org.quartz.impl.triggers.CronTriggerImpl#updateAfterMisfire(Calendar)\n     * @see org.quartz.impl.triggers.DailyTimeIntervalTriggerImpl#updateAfterMisfire(Calendar)\n     * @see org.quartz.impl.triggers.CalendarIntervalTriggerImpl#updateAfterMisfire(Calendar)\n     */\n    int MISFIRE_INSTRUCTION_SMART_POLICY = 0;\n    \n    /**\n     * Instructs the <code>{@link Scheduler}</code> that the \n     * <code>Trigger</code> will never be evaluated for a misfire situation, \n     * and that the scheduler will simply try to fire it as soon as it can, \n     * and then update the Trigger as if it had fired at the proper time. \n     * \n     * <p>NOTE: if a trigger uses this instruction, and it has missed \n     * several of its scheduled firings, then several rapid firings may occur \n     * as the trigger attempt to catch back up to where it would have been. \n     * For example, a SimpleTrigger that fires every 15 seconds which has \n     * misfired for 5 minutes will fire 20 times once it gets the chance to \n     * fire.</p>\n     */\n    int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;\n    \n    /**\n     * The default value for priority.\n     */\n    int DEFAULT_PRIORITY = 5;\n\n    TriggerKey getKey();\n\n    JobKey getJobKey();\n    \n    /**\n     * Return the description given to the <code>Trigger</code> instance by\n     * its creator (if any).\n     * \n     * @return null if no description was set.\n     */\n    String getDescription();\n\n    /**\n     * Get the name of the <code>{@link Calendar}</code> associated with this\n     * Trigger.\n     * \n     * @return <code>null</code> if there is no associated Calendar.\n     */\n    String getCalendarName();\n\n    /**\n     * Get the <code>JobDataMap</code> that is associated with the \n     * <code>Trigger</code>.\n     * \n     * <p>\n     * Changes made to this map during job execution are not re-persisted, and\n     * in fact typically result in an <code>IllegalStateException</code>.\n     * </p>\n     */\n    JobDataMap getJobDataMap();\n\n    /**\n     * The priority of a <code>Trigger</code> acts as a tiebreaker such that if \n     * two <code>Trigger</code>s have the same scheduled fire time, then the\n     * one with the higher priority will get first access to a worker\n     * thread.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>5</code>.\n     * </p>\n     * \n     * @see #DEFAULT_PRIORITY\n     */\n    int getPriority();\n\n    /**\n     * Used by the <code>{@link Scheduler}</code> to determine whether or not\n     * it is possible for this <code>Trigger</code> to fire again.\n     * \n     * <p>\n     * If the returned value is <code>false</code> then the <code>Scheduler</code>\n     * may remove the <code>Trigger</code> from the <code>{@link org.quartz.spi.JobStore}</code>.\n     * </p>\n     */\n    boolean mayFireAgain();\n\n    /**\n     * Get the time at which the <code>Trigger</code> should occur.\n     */\n    Date getStartTime();\n\n    /**\n     * Get the time at which the <code>Trigger</code> should quit repeating -\n     * regardless of any remaining repeats (based on the trigger's particular \n     * repeat settings). \n     * \n     * @see #getFinalFireTime()\n     */\n    Date getEndTime();\n\n    /**\n     * Returns the next time at which the <code>Trigger</code> is scheduled to fire. If\n     * the trigger will not fire again, <code>null</code> will be returned.  Note that\n     * the time returned can possibly be in the past, if the time that was computed\n     * for the trigger to next fire has already arrived, but the scheduler has not yet\n     * been able to fire the trigger (which would likely be due to lack of resources\n     * e.g. threads).\n     *\n     * <p>The value returned is not guaranteed to be valid until after the <code>Trigger</code>\n     * has been added to the scheduler.\n     * </p>\n     *\n     * @see TriggerUtils#computeFireTimesBetween(org.quartz.spi.OperableTrigger, Calendar, java.util.Date, java.util.Date)\n     */\n    Date getNextFireTime();\n\n    /**\n     * Returns the previous time at which the <code>Trigger</code> fired.\n     * If the trigger has not yet fired, <code>null</code> will be returned.\n     */\n    Date getPreviousFireTime();\n\n    /**\n     * Returns the next time at which the <code>Trigger</code> will fire,\n     * after the given time. If the trigger will not fire after the given time,\n     * <code>null</code> will be returned.\n     */\n    Date getFireTimeAfter(Date afterTime);\n\n    /**\n     * Returns the last time at which the <code>Trigger</code> will fire, if\n     * the Trigger will repeat indefinitely, null will be returned.\n     * \n     * <p>\n     * Note that the return time *may* be in the past.\n     * </p>\n     */\n    Date getFinalFireTime();\n\n    /**\n     * Get the instruction the <code>Scheduler</code> should be given for\n     * handling misfire situations for this <code>Trigger</code>- the\n     * concrete <code>Trigger</code> type that you are using will have\n     * defined a set of additional <code>MISFIRE_INSTRUCTION_XXX</code>\n     * constants that may be set as this property's value.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.\n     * </p>\n     * \n     * @see #MISFIRE_INSTRUCTION_SMART_POLICY\n     * @see SimpleTrigger\n     * @see CronTrigger\n     */\n    int getMisfireInstruction();\n\n    /**\n     * Get a {@link TriggerBuilder} that is configured to produce a \n     * <code>Trigger</code> identical to this one.\n     * \n     * @see #getScheduleBuilder()\n     */\n    TriggerBuilder<? extends Trigger> getTriggerBuilder();\n    \n    /**\n     * Get a {@link ScheduleBuilder} that is configured to produce a \n     * schedule identical to this trigger's schedule.\n     * \n     * @see #getTriggerBuilder()\n     */\n    ScheduleBuilder<? extends Trigger> getScheduleBuilder();\n\n    /**\n     * Trigger equality is based upon the equality of the TriggerKey.\n     * \n     * @return true if the key of this Trigger equals that of the given Trigger.\n     */\n    boolean equals(Object other);\n    \n    /**\n     * <p>\n     * Compare the next fire time of this <code>Trigger</code> to that of\n     * another by comparing their keys, or in other words, sorts them\n     * according to the natural (i.e. alphabetical) order of their keys.\n     * </p>\n     */\n    int compareTo(Trigger other);\n\n    /**\n     * A Comparator that compares trigger's next fire times, or in other words,\n     * sorts them according to earliest next fire time.  If the fire times are\n     * the same, then the triggers are sorted according to priority (highest\n     * value first), if the priorities are the same, then they are sorted\n     * by key.\n     */\n    class TriggerTimeComparator implements Comparator<Trigger>, Serializable {\n      \n        private static final long serialVersionUID = -3904243490805975570L;\n        \n        // This static method exists for comparator in TC clustered quartz\n        public static int compare(Date nextFireTime1, int priority1, TriggerKey key1, Date nextFireTime2, int priority2, TriggerKey key2) {\n            if (nextFireTime1 != null || nextFireTime2 != null) {\n                if (nextFireTime1 == null) {\n                    return 1;\n                }\n\n                if (nextFireTime2 == null) {\n                    return -1;\n                }\n\n                if(nextFireTime1.before(nextFireTime2)) {\n                    return -1;\n                }\n\n                if(nextFireTime1.after(nextFireTime2)) {\n                    return 1;\n                }\n            }\n\n            int comp = priority2 - priority1;\n            if (comp != 0) {\n                return comp;\n            }\n\n            return key1.compareTo(key2);\n        }\n\n\n        public int compare(Trigger t1, Trigger t2) {\n            return compare(t1.getNextFireTime(), t1.getPriority(), t1.getKey(), t2.getNextFireTime(), t2.getPriority(), t2.getKey());\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/TriggerBuilder.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.time.Instant;\nimport java.util.Date;\n\nimport org.quartz.spi.MutableTrigger;\nimport org.quartz.utils.Key;\n\n/**\n * <code>TriggerBuilder</code> is used to instantiate {@link Trigger}s.\n * \n * <p>The builder will always try to keep itself in a valid state, with \n * reasonable defaults set for calling build() at any point.  For instance\n * if you do not invoke <i>withSchedule(..)</i> method, a default schedule\n * of firing once immediately will be used.  As another example, if you\n * do not invoked <i>withIdentity(..)</i> a trigger name will be generated\n * for you.</p>\n *  \n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *  \n * @see JobBuilder\n * @see ScheduleBuilder\n * @see DateBuilder \n * @see Trigger\n */\npublic class TriggerBuilder<T extends Trigger> {\n\n    private TriggerKey key;\n    private String description;\n    private Date startTime = new Date();\n    private Date endTime;\n    private int priority = Trigger.DEFAULT_PRIORITY;\n    private String calendarName;\n    private JobKey jobKey;\n    private JobDataMap jobDataMap = new JobDataMap();\n    \n    private ScheduleBuilder<?> scheduleBuilder = null;\n    \n    private TriggerBuilder() {\n        \n    }\n    \n    /**\n     * Create a new TriggerBuilder with which to define a \n     * specification for a Trigger.\n     * \n     * @return the new TriggerBuilder\n     */\n    public static TriggerBuilder<Trigger> newTrigger() {\n        return new TriggerBuilder<>();\n    }\n    \n    /**\n     * Produce the <code>Trigger</code>.\n     * \n     * @return a Trigger that meets the specifications of the builder.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T build() {\n\n        if(scheduleBuilder == null)\n            scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();\n        MutableTrigger trig = scheduleBuilder.build();\n        \n        trig.setCalendarName(calendarName);\n        trig.setDescription(description);\n        trig.setStartTime(startTime);\n        trig.setEndTime(endTime);\n        if(key == null)\n            key = new TriggerKey(Key.createUniqueName(null), null);\n        trig.setKey(key); \n        if(jobKey != null)\n            trig.setJobKey(jobKey);\n        trig.setPriority(priority);\n        \n        if(!jobDataMap.isEmpty())\n            trig.setJobDataMap(jobDataMap);\n        \n        return (T) trig;\n    }\n\n    /**\n     * Use a <code>TriggerKey</code> with the given name and default group to\n     * identify the Trigger.\n     * \n     * <p>If none of the 'withIdentity' methods are set on the TriggerBuilder,\n     * then a random, unique TriggerKey will be generated.</p>\n     * \n     * @param name the name element for the Trigger's TriggerKey\n     * @return the updated TriggerBuilder\n     * @see TriggerKey\n     * @see Trigger#getKey()\n     */\n    public TriggerBuilder<T> withIdentity(String name) {\n        key = new TriggerKey(name, null);\n        return this;\n    }  \n    \n    /**\n     * Use a TriggerKey with the given name and group to\n     * identify the Trigger.\n     * \n     * <p>If none of the 'withIdentity' methods are set on the TriggerBuilder,\n     * then a random, unique TriggerKey will be generated.</p>\n     * \n     * @param name the name element for the Trigger's TriggerKey\n     * @param group the group element for the Trigger's TriggerKey\n     * @return the updated TriggerBuilder\n     * @see TriggerKey\n     * @see Trigger#getKey()\n     */\n    public TriggerBuilder<T> withIdentity(String name, String group) {\n        key = new TriggerKey(name, group);\n        return this;\n    }\n    \n    /**\n     * Use the given TriggerKey to identify the Trigger.  \n     * \n     * <p>If none of the 'withIdentity' methods are set on the TriggerBuilder,\n     * then a random, unique TriggerKey will be generated.</p>\n     * \n     * @param triggerKey the TriggerKey for the Trigger to be built\n     * @return the updated TriggerBuilder\n     * @see TriggerKey\n     * @see Trigger#getKey()\n     */\n    public TriggerBuilder<T> withIdentity(TriggerKey triggerKey) {\n        this.key = triggerKey;\n        return this;\n    }\n\n    /**\n     * Set the given (human-meaningful) description of the Trigger.\n     * \n     * @param triggerDescription the description for the Trigger\n     * @return the updated TriggerBuilder\n     * @see Trigger#getDescription()\n     */\n    public TriggerBuilder<T> withDescription(String triggerDescription) {\n        this.description = triggerDescription;\n        return this;\n    }\n    \n    /**\n     * Set the Trigger's priority.  When more than one Trigger have the same\n     * fire time, the scheduler will fire the one with the highest priority\n     * first.\n     * \n     * @param triggerPriority the priority for the Trigger\n     * @return the updated TriggerBuilder\n     * @see Trigger#DEFAULT_PRIORITY\n     * @see Trigger#getPriority()\n     */\n    public TriggerBuilder<T> withPriority(int triggerPriority) {\n        this.priority = triggerPriority;\n        return this;\n    }\n\n    /**\n     * Set the name of the {@link Calendar} that should be applied to this\n     * Trigger's schedule.\n     * \n     * @param calName the name of the Calendar to reference.\n     * @return the updated TriggerBuilder\n     * @see Calendar\n     * @see Trigger#getCalendarName()\n     */\n    public TriggerBuilder<T> modifiedByCalendar(String calName) {\n        this.calendarName = calName;\n        return this;\n    }\n    \n    /**\n     * Set the time the Trigger should start at - the trigger may or may\n     * not fire at this time - depending upon the schedule configured for\n     * the Trigger.  However the Trigger will NOT fire before this time,\n     * regardless of the Trigger's schedule.\n     *  \n     * @param triggerStartTime the start time for the Trigger.\n     * @return the updated TriggerBuilder\n     * @see Trigger#getStartTime()\n     * @see DateBuilder\n     */\n    public TriggerBuilder<T> startAt(Date triggerStartTime) {\n        this.startTime = triggerStartTime;\n        return this;\n    }\n\n\n    /**\n     * Change the Instant type to Date type to set the trigger start at.\n     *\n     * @param triggerStartTime the start time for the Trigger but type is Instant\n     * @return the updated TriggerBuilder\n     * @see Trigger#getStartTime()\n     * @see DateBuilder\n     */\n    public TriggerBuilder<T> startAt(Instant triggerStartTime){\n        this.startTime = Date.from(triggerStartTime);\n        return this;\n    }\n    \n    /**\n     * Set the time the Trigger should start at to the current moment - \n     * the trigger may or may not fire at this time - depending upon the \n     * schedule configured for the Trigger.  \n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getStartTime()\n     */\n    public TriggerBuilder<T> startNow() {\n        this.startTime = new Date();\n        return this;\n    }\n\n    /**\n     * Set the time at which the Trigger will no longer fire - even if it's\n     * schedule has remaining repeats.    \n     *  \n     * @param triggerEndTime the end time for the Trigger.  If null, the end time is indefinite.\n     * @return the updated TriggerBuilder\n     * @see Trigger#getEndTime()\n     * @see DateBuilder\n     */\n    public TriggerBuilder<T> endAt(Date triggerEndTime) {\n        this.endTime = triggerEndTime;\n        return this;\n    }\n\n    /**\n     * Set the {@link ScheduleBuilder} that will be used to define the \n     * Trigger's schedule.\n     * \n     * <p>The particular <code>SchedulerBuilder</code> used will dictate\n     * the concrete type of Trigger that is produced by the TriggerBuilder.</p>\n     * \n     * @param schedBuilder the SchedulerBuilder to use.\n     * @return the updated TriggerBuilder\n     * @see ScheduleBuilder\n     * @see SimpleScheduleBuilder\n     * @see CronScheduleBuilder\n     * @see CalendarIntervalScheduleBuilder\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder) {\n        this.scheduleBuilder = schedBuilder;\n        return (TriggerBuilder<SBT>) this;\n    }\n\n    /**\n     * Set the identity of the Job which should be fired by the produced \n     * Trigger.\n     * \n     * @param keyOfJobToFire the identity of the Job to fire.\n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobKey()\n     */\n    public TriggerBuilder<T> forJob(JobKey keyOfJobToFire) {\n        this.jobKey = keyOfJobToFire;\n        return this;\n    }\n    \n    /**\n     * Set the identity of the Job which should be fired by the produced \n     * Trigger - a <code>JobKey</code> will be produced with the given\n     * name and default group.\n     * \n     * @param jobName the name of the job (in default group) to fire. \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobKey()\n     */\n    public TriggerBuilder<T> forJob(String jobName) {\n        this.jobKey = new JobKey(jobName, null);\n        return this;\n    }\n    \n    /**\n     * Set the identity of the Job which should be fired by the produced \n     * Trigger - a <code>JobKey</code> will be produced with the given\n     * name and group.\n     * \n     * @param jobName the name of the job to fire. \n     * @param jobGroup the group of the job to fire. \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobKey()\n     */\n    public TriggerBuilder<T> forJob(String jobName, String jobGroup) {\n        this.jobKey = new JobKey(jobName, jobGroup);\n        return this;\n    }\n    \n    /**\n     * Set the identity of the Job which should be fired by the produced \n     * Trigger, by extracting the JobKey from the given job.\n     * \n     * @param jobDetail the Job to fire.\n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobKey()\n     */\n    public TriggerBuilder<T> forJob(JobDetail jobDetail) {\n        JobKey k = jobDetail.getKey();\n        if(k.getName() == null)\n            throw new IllegalArgumentException(\"The given job has not yet had a name assigned to it.\");\n        this.jobKey = k;\n        return this;\n    }\n\n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, String value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, Integer value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, Long value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, Float value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, Double value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Add the given key-value pair to the Trigger's {@link JobDataMap}.\n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(String dataKey, Boolean value) {\n        jobDataMap.put(dataKey, value);\n        return this;\n    }\n    \n    /**\n     * Set the Trigger's {@link JobDataMap}, adding any values to it\n     * that were already set on this TriggerBuilder using any of the\n     * other 'usingJobData' methods. \n     * \n     * @return the updated TriggerBuilder\n     * @see Trigger#getJobDataMap()\n     */\n    public TriggerBuilder<T> usingJobData(JobDataMap newJobDataMap) {\n        // add any existing data to this new map\n        for(String dataKey: jobDataMap.keySet()) {\n            newJobDataMap.put(dataKey, jobDataMap.get(dataKey));\n        }\n        jobDataMap = newJobDataMap; // set new map as the map to use\n        return this;\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/TriggerKey.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.utils.Key;\n\n/**\n * Uniquely identifies a {@link Trigger}.\n * \n * <p>Keys are composed of both a name and group, and the name must be unique\n * within the group.  If only a name is specified then the default group\n * name will be used.</p> \n *\n *\n * <p>Quartz provides a builder-style API for constructing scheduling-related\n * entities via a Domain-Specific Language (DSL).  The DSL can best be\n * utilized through the usage of static imports of the methods on the classes\n * <code>TriggerBuilder</code>, <code>JobBuilder</code>, \n * <code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \n * and the various <code>ScheduleBuilder</code> implementations.</p>\n * \n * <p>Client code can then use the DSL to write code such as this:</p>\n * <pre>\n *         JobDetail job = newJob(MyJob.class)\n *             .withIdentity(\"myJob\")\n *             .build();\n *             \n *         Trigger trigger = newTrigger() \n *             .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n *             .withSchedule(simpleSchedule()\n *                 .withIntervalInHours(1)\n *                 .repeatForever())\n *             .startAt(futureDate(10, MINUTES))\n *             .build();\n *         \n *         scheduler.scheduleJob(job, trigger);\n * </pre>\n *  \n * \n * @see Trigger\n * @see Key#DEFAULT_GROUP\n */\npublic final class TriggerKey extends Key<TriggerKey> {\n  \n    private static final long serialVersionUID = 8070357886703449660L;\n\n    public TriggerKey(String name) {\n        super(name, null);\n    }\n\n    public TriggerKey(String name, String group) {\n        super(name, group);\n    }\n\n    public static TriggerKey triggerKey(String name) {\n        return new TriggerKey(name, null);\n    }\n    \n    public static TriggerKey triggerKey(String name, String group) {\n        return new TriggerKey(name, group);\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/TriggerListener.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport org.quartz.Trigger.CompletedExecutionInstruction;\n\n/**\n * The interface to be implemented by classes that want to be informed when a\n * <code>{@link Trigger}</code> fires. In general, applications that use a\n * <code>Scheduler</code> will not have use for this mechanism.\n * \n * @see ListenerManager#addTriggerListener(TriggerListener, Matcher)\n * @see Matcher\n * @see Trigger\n * @see JobListener\n * @see JobExecutionContext\n * \n * @author James House\n */\npublic interface TriggerListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name of the <code>TriggerListener</code>.\n     * </p>\n     */\n    String getName();\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has fired, and it's associated <code>{@link org.quartz.JobDetail}</code>\n     * is about to be executed.\n     * </p>\n     * \n     * <p>\n     * It is called before the <code>vetoJobExecution(..)</code> method of this\n     * interface.\n     * </p>\n     * \n     * @param trigger\n     *          The <code>Trigger</code> that has fired.\n     * @param context\n     *          The <code>JobExecutionContext</code> that will be passed to\n     *          the <code>Job</code>'s<code>execute(xx)</code> method.\n     */\n    void triggerFired(Trigger trigger, JobExecutionContext context);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has fired, and it's associated <code>{@link org.quartz.JobDetail}</code>\n     * is about to be executed.  If the implementation vetoes the execution (via\n     * returning <code>true</code>), the job's execute method will not be called.\n     * </p>\n     * \n     * <p>\n     * It is called after the <code>triggerFired(..)</code> method of this\n     * interface.\n     * </p>\n     * \n     * @param trigger\n     *          The <code>Trigger</code> that has fired.\n     * @param context\n     *          The <code>JobExecutionContext</code> that will be passed to\n     *          the <code>Job</code>'s<code>execute(xx)</code> method.\n     */\n    boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);\n\n    \n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has misfired.\n     * </p>\n     * \n     * <p>\n     * Consideration should be given to how much time is spent in this method,\n     * as it will affect all triggers that are misfiring.  If you have lots\n     * of triggers misfiring at once, it could be an issue it this method\n     * does a lot.\n     * </p>\n     * \n     * @param trigger\n     *          The <code>Trigger</code> that has misfired.\n     */\n    void triggerMisfired(Trigger trigger);\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>\n     * has fired, it's associated <code>{@link org.quartz.JobDetail}</code>\n     * has been executed, and it's <code>triggered(xx)</code> method has been\n     * called.\n     * </p>\n     * \n     * @param trigger\n     *          The <code>Trigger</code> that was fired.\n     * @param context\n     *          The <code>JobExecutionContext</code> that was passed to the\n     *          <code>Job</code>'s<code>execute(xx)</code> method.\n     * @param triggerInstructionCode\n     *          the result of the call on the <code>Trigger</code>'s<code>triggered(xx)</code>\n     *          method.\n     */\n    void triggerComplete(Trigger trigger, JobExecutionContext context,\n            CompletedExecutionInstruction triggerInstructionCode);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/TriggerUtils.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\nimport java.util.Date;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * Convenience and utility methods for working with <code>{@link Trigger}s</code>.\n * \n * \n * @see CronTrigger\n * @see SimpleTrigger\n * @see DateBuilder\n * \n * @author James House\n */\npublic class TriggerUtils {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Private constructor because this is a pure utility class.\n     */\n    private TriggerUtils() {\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Returns a list of Dates that are the next fire times of a \n     * <code>Trigger</code>.\n     * The input trigger will be cloned before any work is done, so you need\n     * not worry about its state being altered by this method.\n     * \n     * @param trigger\n     *          The trigger upon which to do the work\n     * @param cal\n     *          The calendar to apply to the trigger's schedule\n     * @param numTimes\n     *          The number of next fire times to produce\n     * @return List of java.util.Date objects\n     */\n    public static List<Date> computeFireTimes(OperableTrigger trigger, org.quartz.Calendar cal,\n            int numTimes) {\n        LinkedList<Date> lst = new LinkedList<>();\n\n        OperableTrigger t = (OperableTrigger) trigger.clone();\n\n        if (t.getNextFireTime() == null) {\n            t.computeFirstFireTime(cal);\n        }\n\n        for (int i = 0; i < numTimes; i++) {\n            Date d = t.getNextFireTime();\n            if (d != null) {\n                lst.add(d);\n                t.triggered(cal);\n            } else {\n                break;\n            }\n        }\n\n        return java.util.Collections.unmodifiableList(lst);\n    }\n    \n    /**\n     * Compute the <code>Date</code> that is 1 second after the Nth firing of \n     * the given <code>Trigger</code>, taking the trigger's associated \n     * <code>Calendar</code> into consideration.\n     *  \n     * The input trigger will be cloned before any work is done, so you need\n     * not worry about its state being altered by this method.\n     * \n     * @param trigger\n     *          The trigger upon which to do the work\n     * @param cal\n     *          The calendar to apply to the trigger's schedule\n     * @param numTimes\n     *          The number of next fire times to produce\n     * @return the computed Date, or null if the trigger (as configured) will not fire that many times.\n     */\n    public static Date computeEndTimeToAllowParticularNumberOfFirings(OperableTrigger trigger, org.quartz.Calendar cal, \n            int numTimes) {\n\n        OperableTrigger t = (OperableTrigger) trigger.clone();\n\n        if (t.getNextFireTime() == null) {\n            t.computeFirstFireTime(cal);\n        }\n        \n        int c = 0;\n        Date endTime = null;\n        \n        for (int i = 0; i < numTimes; i++) {\n            Date d = t.getNextFireTime();\n            if (d != null) {\n                c++;\n                t.triggered(cal);\n                if(c == numTimes)\n                    endTime = d;\n            } else {\n                break;\n            }\n        }\n        \n        if(endTime == null)\n            return null;\n        \n        endTime = new Date(endTime.getTime() + 1000L);\n        \n        return endTime;\n    }\n\n    /**\n     * Returns a list of Dates that are the next fire times of a \n     * <code>Trigger</code>\n     * that fall within the given date range. The input trigger will be cloned\n     * before any work is done, so you need not worry about its state being\n     * altered by this method.\n     * \n     * <p>\n     * NOTE: if this is a trigger that has previously fired within the given\n     * date range, then firings which have already occurred will not be listed\n     * in the output List.\n     * </p>\n     * \n     * @param trigger\n     *          The trigger upon which to do the work\n     * @param cal\n     *          The calendar to apply to the trigger's schedule\n     * @param from\n     *          The starting date at which to find fire times\n     * @param to\n     *          The ending date at which to stop finding fire times\n     * @return List of java.util.Date objects\n     */\n    public static List<Date> computeFireTimesBetween(OperableTrigger trigger,\n            org.quartz.Calendar cal, Date from, Date to) {\n        LinkedList<Date> lst = new LinkedList<>();\n\n        OperableTrigger t = (OperableTrigger) trigger.clone();\n\n        if (t.getNextFireTime() == null) {\n            t.setStartTime(from);\n            t.setEndTime(to);\n            t.computeFirstFireTime(cal);\n        }\n\n        while (true) {\n            Date d = t.getNextFireTime();\n            if (d != null) {\n                if (d.before(from)) {\n                    t.triggered(cal);\n                    continue;\n                }\n                if (d.after(to)) {\n                    break;\n                }\n                lst.add(d);\n                t.triggered(cal);\n            } else {\n                break;\n            }\n        }\n\n        return java.util.Collections.unmodifiableList(lst);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/UnableToInterruptJobException.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz;\n\n/**\n * An exception that is thrown to indicate that a call to \n * InterruptableJob.interrupt() failed without interrupting the Job.\n * \n * @see org.quartz.InterruptableJob#interrupt()\n * \n * @author James House\n */\npublic class UnableToInterruptJobException extends SchedulerException {\n  \n    private static final long serialVersionUID = -490863760696463776L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>UnableToInterruptJobException</code> with the given message.\n     * </p>\n     */\n    public UnableToInterruptJobException(String msg) {\n        super(msg);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>UnableToInterruptJobException</code> with the given cause.\n     * </p>\n     */\n    public UnableToInterruptJobException(Throwable cause) {\n        super(cause);\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/commonj/WorkManagerThreadExecutor.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n package org.quartz.commonj;\n\nimport commonj.work.Work;\nimport commonj.work.WorkManager;\nimport org.quartz.spi.ThreadExecutor;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\n\n/**\n * CommonJ WorkManager implementation of hacked Quartz ThreadExecutor class.\n * This class schedules work on a WorkManager which is looked up in JNDI. The\n * advantage is that all the work performed is done on a managed thread which is\n * required by WebSphere, see <a\n * href=\"http://jira.opensymphony.com/browse/QUARTZ-743\">QUARTZ-743</a> for\n * details.\n *\n * @author matt.accola\n * @version $Revision$ $Date$\n */\npublic class WorkManagerThreadExecutor implements ThreadExecutor {\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    private String workManagerName;\n    private WorkManager workManager;\n\n    public void execute(Thread thread) {\n        Work work = new org.quartz.commonj.DelegatingWork(thread);\n        try {\n            this.workManager.schedule(work);\n        } catch (Exception e) {\n            log.error(\"Error attempting to schedule QuartzSchedulerThread: {}\", e.getMessage(), e);\n        }\n    }\n\n    public void initialize() {\n        try {\n            this.workManager = (WorkManager) new InitialContext().lookup(workManagerName);\n        } catch (NamingException e) {\n            throw new IllegalStateException(\"Could not locate WorkManager: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Sets the JNDI name of the work manager to use.\n     *\n     * @param workManagerName the JNDI name to use to lookup the work manager\n     */\n    public void setWorkManagerName(String workManagerName) {\n        this.workManagerName = workManagerName;\n    }\n\n}\n\nclass DelegatingWork implements Work {\n\n    private final Runnable delegate;\n\n    /**\n     * Create a new DelegatingWork.\n     *\n     * @param delegate the Runnable implementation to delegate to\n     */\n    public DelegatingWork(Runnable delegate) {\n        this.delegate = delegate;\n    }\n\n    /**\n     * @return the wrapped Runnable implementation.\n     */\n    public final Runnable getDelegate() {\n        return this.delegate;\n    }\n\n    /**\n     * Delegates execution to the underlying Runnable.\n     */\n    public void run() {\n        this.delegate.run();\n    }\n\n    public boolean isDaemon() {\n        return false;\n    }\n\n    /**\n     * This implementation is empty, since we expect the Runnable to terminate\n     * based on some specific shutdown signal.\n     */\n    public void release() {\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/JobExecutionProcessException.java",
    "content": "package org.quartz.core;\n\nimport static org.quartz.core.JobExecutionProcessException.ProcessErrorMessage.JobExecution;\nimport static org.quartz.core.JobExecutionProcessException.ProcessErrorMessage.JobListenerExecution;\nimport static org.quartz.core.JobExecutionProcessException.ProcessErrorMessage.TriggerListenerExecution;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobListener;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerListener;\nimport org.quartz.TriggerListener;\n\n/**\n * This exception is thrown when an error occurs during execution:\n * <ul>\n *     <li><code>Job execution</code></li>\n *     <li><code>{@link JobListener} methods</code></li>\n *     <li><code>{@link TriggerListener} methods</code></li>\n * </ul>\n * The exception ensures that the job execution context is transferred to the implementation of the error\n * handling method of the scheduler listener <code>{@link org.quartz.SchedulerListener#schedulerError(String, SchedulerException)}</code>,\n * to try to fix the problem\n */\npublic class JobExecutionProcessException extends SchedulerException\n{\n    enum ProcessErrorMessage\n    {\n        JobExecution(\"Job threw an unhandled exception\"),\n        JobListenerExecution(\"JobListener '%s' threw exception: %s.\"),\n        TriggerListenerExecution(\"TriggerListener '%s' threw exception: %s.\");\n\n        private final String errorMsg;\n\n        ProcessErrorMessage(String errorMsg)\n        {\n            this.errorMsg = errorMsg;\n        }\n\n        public String getErrorMsg()\n        {\n            return errorMsg;\n        }\n    }\n\n    /** The job execution context. */\n    private final JobExecutionContext jobExecutionContext;\n\n    public JobExecutionProcessException(JobExecutionContext jobExecutionContext, Throwable cause)\n    {\n        super(JobExecution.errorMsg, cause);\n        this.jobExecutionContext = jobExecutionContext;\n    }\n\n    public JobExecutionProcessException(JobListener listener, JobExecutionContext jobExecutionContext, Throwable cause)\n    {\n        super(String.format(JobListenerExecution.getErrorMsg(), listener.getName(), cause.getMessage()), cause);\n        this.jobExecutionContext = jobExecutionContext;\n    }\n\n    public JobExecutionProcessException(TriggerListener listener, JobExecutionContext jobExecutionContext, Throwable cause)\n    {\n        super(String.format(TriggerListenerExecution.getErrorMsg(), listener.getName(), cause.getMessage()), cause);\n        this.jobExecutionContext = jobExecutionContext;\n    }\n\n    public JobExecutionContext getJobExecutionContext()\n    {\n        return jobExecutionContext;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/JobRunShell.java",
    "content": "\n/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.core;\n\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.impl.JobExecutionContextImpl;\nimport org.quartz.listeners.SchedulerListenerSupport;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * JobRunShell instances are responsible for providing the 'safe' environment\n * for <code>Job</code> s to run in, and for performing all of the work of\n * executing the <code>Job</code>, catching ANY thrown exceptions, updating\n * the <code>Trigger</code> with the <code>Job</code>'s completion code,\n * etc.\n * </p>\n *\n * <p>\n * A <code>JobRunShell</code> instance is created by a <code>JobRunShellFactory</code>\n * on behalf of the <code>QuartzSchedulerThread</code> which then runs the\n * shell in a thread from the configured <code>ThreadPool</code> when the\n * scheduler determines that a <code>Job</code> has been triggered.\n * </p>\n *\n * @see JobRunShellFactory\n * @see org.quartz.core.QuartzSchedulerThread\n * @see org.quartz.Job\n * @see org.quartz.Trigger\n *\n * @author James House\n */\npublic class JobRunShell extends SchedulerListenerSupport implements Runnable {\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected JobExecutionContextImpl jec = null;\n\n    protected QuartzScheduler qs = null;\n    \n    protected TriggerFiredBundle firedTriggerBundle;\n\n    protected Scheduler scheduler;\n\n    protected volatile boolean shutdownRequested = false;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a JobRunShell instance with the given settings.\n     * </p>\n     *\n     * @param scheduler\n     *          The <code>Scheduler</code> instance that should be made\n     *          available within the <code>JobExecutionContext</code>.\n     */\n    public JobRunShell(Scheduler scheduler, TriggerFiredBundle bundle) {\n        this.scheduler = scheduler;\n        this.firedTriggerBundle = bundle;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    @Override\n    public void schedulerShuttingdown() {\n        requestShutdown();\n    }\n\n    @Override\n    protected Logger getLog() {\n        return log;\n    }\n\n    public void initialize(QuartzScheduler sched)\n        throws SchedulerException {\n        this.qs = sched;\n\n        Job job;\n        JobDetail jobDetail = firedTriggerBundle.getJobDetail();\n\n        try {\n            job = sched.getJobFactory().newJob(firedTriggerBundle, scheduler);\n        } catch (SchedulerException se) {\n            sched.notifySchedulerListenersError(\n                    \"An error occurred instantiating job to be executed. job= '\"\n                            + jobDetail.getKey() + \"'\", se);\n            throw se;\n        } catch (Throwable ncdfe) { // such as NoClassDefFoundError\n            SchedulerException se = new SchedulerException(\n                    \"Problem instantiating class '\"\n                            + jobDetail.getJobClass().getName() + \"' - \", ncdfe);\n            sched.notifySchedulerListenersError(\n                    \"An error occurred instantiating job to be executed. job= '\"\n                            + jobDetail.getKey() + \"'\", se);\n            throw se;\n        }\n\n        this.jec = new JobExecutionContextImpl(scheduler, firedTriggerBundle, job);\n    }\n\n    public void requestShutdown() {\n        shutdownRequested = true;\n    }\n\n    public void run() {\n        qs.addInternalSchedulerListener(this);\n\n        try {\n            OperableTrigger trigger = (OperableTrigger) jec.getTrigger();\n            JobDetail jobDetail = jec.getJobDetail();\n\n            do {\n\n                JobExecutionException jobExEx = null;\n                Job job = jec.getJobInstance();\n\n                try {\n                    begin();\n                } catch (SchedulerException se) {\n                    qs.notifySchedulerListenersError(\"Error executing Job (\"\n                            + jec.getJobDetail().getKey()\n                            + \": couldn't begin execution.\", se);\n                    break;\n                }\n\n                // notify job & trigger listeners...\n                try {\n                    if (!notifyListenersBeginning(jec)) {\n                        break;\n                    }\n                } catch(VetoedException ve) {\n                    try {\n                        CompletedExecutionInstruction instCode = trigger.executionComplete(jec, null);\n                        qs.notifyJobStoreJobVetoed(trigger, jobDetail, instCode);\n                        \n                        // QTZ-205\n                        // Even if trigger got vetoed, we still needs to check to see if it's the trigger's finalized run or not.\n                        if (jec.getTrigger().getNextFireTime() == null) {\n                            qs.notifySchedulerListenersFinalized(jec.getTrigger());\n                        }\n\n                        complete(true);\n                    } catch (SchedulerException se) {\n                        qs.notifySchedulerListenersError(\"Error during veto of Job (\"\n                                + jec.getJobDetail().getKey()\n                                + \": couldn't finalize execution.\", se);\n                    }\n                    break;\n                }\n\n                long startTime = System.currentTimeMillis();\n                long endTime;\n\n                // execute the job\n                try {\n                    log.debug(\"Calling execute on job {}\", jobDetail.getKey());\n                    job.execute(jec);\n                    endTime = System.currentTimeMillis();\n                } catch (JobExecutionException jee) {\n                    endTime = System.currentTimeMillis();\n                    jobExEx = jee;\n                    getLog().info(\"Job {} threw a JobExecutionException: \", jobDetail.getKey(), jobExEx);\n                } catch (Throwable e) {\n                    endTime = System.currentTimeMillis();\n                    getLog().error(\"Job {} threw an unhandled Exception: \", jobDetail.getKey(), e);\n                    SchedulerException se = new JobExecutionProcessException(jec, e);\n                    qs.notifySchedulerListenersError(\"Job \"\n                            + jec.getJobDetail().getKey()\n                            + \" threw an exception.\", se);\n                    jobExEx = new JobExecutionException(se, false);\n                }\n\n                jec.setJobRunTime(endTime - startTime);\n\n                // notify all job listeners\n                if (!notifyJobListenersComplete(jec, jobExEx)) {\n                    break;\n                }\n\n                CompletedExecutionInstruction instCode = CompletedExecutionInstruction.NOOP;\n\n                // update the trigger\n                try {\n                    instCode = trigger.executionComplete(jec, jobExEx);\n                } catch (Exception e) {\n                    // If this happens, there's a bug in the trigger...\n                    SchedulerException se = new SchedulerException(\n                            \"Trigger threw an unhandled exception.\", e);\n                    qs.notifySchedulerListenersError(\n                            \"Please report this error to the Quartz developers.\",\n                            se);\n                }\n\n                // notify all trigger listeners\n                if (!notifyTriggerListenersComplete(jec, instCode)) {\n                    break;\n                }\n\n                // update job/trigger or re-execute job\n                if (instCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) {\n                    jec.incrementRefireCount();\n                    try {\n                        complete(false);\n                    } catch (SchedulerException se) {\n                        qs.notifySchedulerListenersError(\"Error executing Job (\"\n                                + jec.getJobDetail().getKey()\n                                + \": couldn't finalize execution.\", se);\n                    }\n                    continue;\n                }\n\n                try {\n                    complete(true);\n                } catch (SchedulerException se) {\n                    qs.notifySchedulerListenersError(\"Error executing Job (\"\n                            + jec.getJobDetail().getKey()\n                            + \": couldn't finalize execution.\", se);\n                    continue;\n                }\n\n                qs.notifyJobStoreJobComplete(trigger, jobDetail, instCode);\n                break;\n            } while (true);\n\n        } finally {\n            qs.removeInternalSchedulerListener(this);\n        }\n    }\n\n    protected void begin() throws SchedulerException {\n    }\n\n    protected void complete(boolean successfulExecution)\n        throws SchedulerException {\n    }\n\n    public void passivate() {\n        jec = null;\n        qs = null;\n    }\n\n    private boolean notifyListenersBeginning(JobExecutionContext jobExCtx) throws VetoedException {\n\n        boolean vetoed;\n\n        // notify all trigger listeners\n        try {\n            vetoed = qs.notifyTriggerListenersFired(jobExCtx);\n        } catch (SchedulerException se) {\n            qs.notifySchedulerListenersError(\n                    \"Unable to notify TriggerListener(s) while firing trigger \"\n                            + \"(Trigger and Job will NOT be fired!). trigger= \"\n                            + jobExCtx.getTrigger().getKey() + \" job= \"\n                            + jobExCtx.getJobDetail().getKey(), se);\n\n            return false;\n        }\n\n        if(vetoed) {\n            try {\n                qs.notifyJobListenersWasVetoed(jobExCtx);\n            } catch (SchedulerException se) {\n                qs.notifySchedulerListenersError(\n                        \"Unable to notify JobListener(s) of vetoed execution \" +\n                        \"while firing trigger (Trigger and Job will NOT be \" +\n                        \"fired!). trigger= \"\n                        + jobExCtx.getTrigger().getKey() + \" job= \"\n                        + jobExCtx.getJobDetail().getKey(), se);\n\n            }\n            throw new VetoedException();\n        }\n\n        // notify all job listeners\n        try {\n            qs.notifyJobListenersToBeExecuted(jobExCtx);\n        } catch (SchedulerException se) {\n            qs.notifySchedulerListenersError(\n                    \"Unable to notify JobListener(s) of Job to be executed: \"\n                            + \"(Job will NOT be executed!). trigger= \"\n                            + jobExCtx.getTrigger().getKey() + \" job= \"\n                            + jobExCtx.getJobDetail().getKey(), se);\n\n            return false;\n        }\n\n        return true;\n    }\n\n    private boolean notifyJobListenersComplete(JobExecutionContext jobExCtx, JobExecutionException jobExEx) {\n        try {\n            qs.notifyJobListenersWasExecuted(jobExCtx, jobExEx);\n        } catch (SchedulerException se) {\n            qs.notifySchedulerListenersError(\n                    \"Unable to notify JobListener(s) of Job that was executed: \"\n                            + \"(error will be ignored). trigger= \"\n                            + jobExCtx.getTrigger().getKey() + \" job= \"\n                            + jobExCtx.getJobDetail().getKey(), se);\n\n            return false;\n        }\n\n        return true;\n    }\n\n    private boolean notifyTriggerListenersComplete(JobExecutionContext jobExCtx, CompletedExecutionInstruction instCode) {\n        try {\n            qs.notifyTriggerListenersComplete(jobExCtx, instCode);\n\n        } catch (SchedulerException se) {\n            qs.notifySchedulerListenersError(\n                    \"Unable to notify TriggerListener(s) of Job that was executed: \"\n                            + \"(error will be ignored). trigger= \"\n                            + jobExCtx.getTrigger().getKey() + \" job= \"\n                            + jobExCtx.getJobDetail().getKey(), se);\n\n            return false;\n        }\n        if (jobExCtx.getTrigger().getNextFireTime() == null) {\n            qs.notifySchedulerListenersFinalized(jobExCtx.getTrigger());\n        }\n\n        return true;\n    }\n\n    static class VetoedException extends Exception {\n\n        private static final long serialVersionUID = 1539955697495918463L;\n\n        public VetoedException() {\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/JobRunShellFactory.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.core;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.TriggerFiredBundle;\n\n/**\n * <p>\n * Responsible for creating the instances of <code>{@link JobRunShell}</code>\n * to be used within the <code>{@link QuartzScheduler}</code> instance.\n * </p>\n * \n * @author James House\n */\npublic interface JobRunShellFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Initialize the factory, providing a handle to the <code>Scheduler</code>\n     * that should be made available within the <code>JobRunShell</code> and\n     * the <code>JobExecutionContext</code> s within it.\n     * </p>\n     */\n    void initialize(Scheduler scheduler)\n        throws SchedulerConfigException;\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>\n     * to obtain instances of <code>{@link JobRunShell}</code>.\n     * </p>\n     */\n    JobRunShell createJobRunShell(TriggerFiredBundle bundle) throws SchedulerException;\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/ListenerManagerImpl.java",
    "content": "package org.quartz.core;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.quartz.JobKey;\nimport org.quartz.JobListener;\nimport org.quartz.ListenerManager;\nimport org.quartz.Matcher;\nimport org.quartz.SchedulerListener;\nimport org.quartz.TriggerKey;\nimport org.quartz.TriggerListener;\nimport org.quartz.impl.matchers.EverythingMatcher;\n\npublic class ListenerManagerImpl implements ListenerManager {\n\n    private final Map<String, JobListener> globalJobListeners = new LinkedHashMap<>(10);\n\n    private final Map<String, TriggerListener> globalTriggerListeners = new LinkedHashMap<>(10);\n\n    private final Map<String, List<Matcher<JobKey>>> globalJobListenersMatchers = new LinkedHashMap<>(10);\n\n    private final Map<String, List<Matcher<TriggerKey>>> globalTriggerListenersMatchers = new LinkedHashMap<>(10);\n\n    private final ArrayList<SchedulerListener> schedulerListeners = new ArrayList<>(10);\n\n    \n    public void addJobListener(JobListener jobListener, Matcher<JobKey> ... matchers) {\n        addJobListener(jobListener, Arrays.asList(matchers));\n    }\n\n    public void addJobListener(JobListener jobListener, List<Matcher<JobKey>> matchers) {\n        if (jobListener.getName() == null || jobListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"JobListener name cannot be empty.\");\n        }\n        \n        synchronized (globalJobListeners) {\n            globalJobListeners.put(jobListener.getName(), jobListener);\n            LinkedList<Matcher<JobKey>> matchersL = new LinkedList<>();\n            if(matchers != null && !matchers.isEmpty())\n                matchersL.addAll(matchers);\n            else\n                matchersL.add(EverythingMatcher.allJobs());\n            \n            globalJobListenersMatchers.put(jobListener.getName(), matchersL);\n        }\n    }\n\n\n    public void addJobListener(JobListener jobListener) {\n        addJobListener(jobListener, EverythingMatcher.allJobs());\n    }\n    \n    public void addJobListener(JobListener jobListener, Matcher<JobKey> matcher) {\n        if (jobListener.getName() == null || jobListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"JobListener name cannot be empty.\");\n        }\n        \n        synchronized (globalJobListeners) {\n            globalJobListeners.put(jobListener.getName(), jobListener);\n            LinkedList<Matcher<JobKey>> matchersL = new LinkedList<>();\n            if(matcher != null)\n                matchersL.add(matcher);\n            else\n                matchersL.add(EverythingMatcher.allJobs());\n            \n            globalJobListenersMatchers.put(jobListener.getName(), matchersL);\n        }\n    }\n\n\n    public boolean addJobListenerMatcher(String listenerName, Matcher<JobKey> matcher) {\n        if(matcher == null)\n            throw new IllegalArgumentException(\"Null value not acceptable.\");\n        \n        synchronized (globalJobListeners) {\n            List<Matcher<JobKey>> matchers = globalJobListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return false;\n            matchers.add(matcher);\n            return true;\n        }\n    }\n\n    public boolean removeJobListenerMatcher(String listenerName, Matcher<JobKey> matcher) {\n        if(matcher == null)\n            throw new IllegalArgumentException(\"Non-null value not acceptable.\");\n        \n        synchronized (globalJobListeners) {\n            List<Matcher<JobKey>> matchers = globalJobListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return false;\n            return matchers.remove(matcher);\n        }\n    }\n\n    public List<Matcher<JobKey>> getJobListenerMatchers(String listenerName) {\n        synchronized (globalJobListeners) {\n            List<Matcher<JobKey>> matchers = globalJobListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return null;\n            return Collections.unmodifiableList(matchers);\n        }\n    }\n\n    public boolean setJobListenerMatchers(String listenerName, List<Matcher<JobKey>> matchers)  {\n        if(matchers == null)\n            throw new IllegalArgumentException(\"Non-null value not acceptable.\");\n        \n        synchronized (globalJobListeners) {\n            List<Matcher<JobKey>> oldMatchers = globalJobListenersMatchers.get(listenerName);\n            if(oldMatchers == null)\n                return false;\n            globalJobListenersMatchers.put(listenerName, matchers);\n            return true;\n        }\n    }\n\n\n    public boolean removeJobListener(String name) {\n        synchronized (globalJobListeners) {\n            return (globalJobListeners.remove(name) != null);\n        }\n    }\n    \n    public List<JobListener> getJobListeners() {\n        synchronized (globalJobListeners) {\n            return java.util.Collections.unmodifiableList(new LinkedList<>(globalJobListeners.values()));\n        }\n    }\n\n    public JobListener getJobListener(String name) {\n        synchronized (globalJobListeners) {\n            return globalJobListeners.get(name);\n        }\n    }\n\n    public void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> ... matchers) {\n        addTriggerListener(triggerListener, Arrays.asList(matchers));\n    }\n    \n    public void addTriggerListener(TriggerListener triggerListener, List<Matcher<TriggerKey>> matchers) {\n        if (triggerListener.getName() == null\n                || triggerListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"TriggerListener name cannot be empty.\");\n        }\n\n        synchronized (globalTriggerListeners) {\n            globalTriggerListeners.put(triggerListener.getName(), triggerListener);\n\n            LinkedList<Matcher<TriggerKey>> matchersL = new LinkedList<>();\n            if(matchers != null && !matchers.isEmpty())\n                matchersL.addAll(matchers);\n            else\n                matchersL.add(EverythingMatcher.allTriggers());\n\n            globalTriggerListenersMatchers.put(triggerListener.getName(), matchersL);\n        }\n    }\n    \n    public void addTriggerListener(TriggerListener triggerListener) {\n        addTriggerListener(triggerListener, EverythingMatcher.allTriggers());\n    }\n\n    public void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> matcher) {\n        if(matcher == null)\n            throw new IllegalArgumentException(\"Null value not acceptable for matcher.\");\n        \n        if (triggerListener.getName() == null\n                || triggerListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"TriggerListener name cannot be empty.\");\n        }\n\n        synchronized (globalTriggerListeners) {\n            globalTriggerListeners.put(triggerListener.getName(), triggerListener);\n            List<Matcher<TriggerKey>> matchers = new LinkedList<>();\n            matchers.add(matcher);\n            globalTriggerListenersMatchers.put(triggerListener.getName(), matchers);\n        }\n    }\n\n    public boolean addTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher) {\n        if(matcher == null)\n            throw new IllegalArgumentException(\"Non-null value not acceptable.\");\n        \n        synchronized (globalTriggerListeners) {\n            List<Matcher<TriggerKey>> matchers = globalTriggerListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return false;\n            matchers.add(matcher);\n            return true;\n        }\n    }\n\n    public boolean removeTriggerListenerMatcher(String listenerName, Matcher<TriggerKey> matcher) {\n        if(matcher == null)\n            throw new IllegalArgumentException(\"Non-null value not acceptable.\");\n        \n        synchronized (globalTriggerListeners) {\n            List<Matcher<TriggerKey>> matchers = globalTriggerListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return false;\n            return matchers.remove(matcher);\n        }\n    }\n\n    public List<Matcher<TriggerKey>> getTriggerListenerMatchers(String listenerName) {\n        synchronized (globalTriggerListeners) {\n            List<Matcher<TriggerKey>> matchers = globalTriggerListenersMatchers.get(listenerName);\n            if(matchers == null)\n                return null;\n            return Collections.unmodifiableList(matchers);\n        }\n    }\n\n    public boolean setTriggerListenerMatchers(String listenerName, List<Matcher<TriggerKey>> matchers)  {\n        if(matchers == null)\n            throw new IllegalArgumentException(\"Non-null value not acceptable.\");\n        \n        synchronized (globalTriggerListeners) {\n            List<Matcher<TriggerKey>> oldMatchers = globalTriggerListenersMatchers.get(listenerName);\n            if(oldMatchers == null)\n                return false;\n            globalTriggerListenersMatchers.put(listenerName, matchers);\n            return true;\n        }\n    }\n\n    public boolean removeTriggerListener(String name) {\n        synchronized (globalTriggerListeners) {\n            return (globalTriggerListeners.remove(name) != null);\n        }\n    }\n    \n\n    public List<TriggerListener> getTriggerListeners() {\n        synchronized (globalTriggerListeners) {\n            return java.util.Collections.unmodifiableList(new LinkedList<>(globalTriggerListeners.values()));\n        }\n    }\n\n    public TriggerListener getTriggerListener(String name) {\n        synchronized (globalTriggerListeners) {\n            return globalTriggerListeners.get(name);\n        }\n    }\n    \n    \n    public void addSchedulerListener(SchedulerListener schedulerListener) {\n        synchronized (schedulerListeners) {\n            schedulerListeners.add(schedulerListener);\n        }\n    }\n\n    public boolean removeSchedulerListener(SchedulerListener schedulerListener) {\n        synchronized (schedulerListeners) {\n            return schedulerListeners.remove(schedulerListener);\n        }\n    }\n\n    public List<SchedulerListener> getSchedulerListeners() {\n        synchronized (schedulerListeners) {\n            return java.util.Collections.unmodifiableList(new ArrayList<>(schedulerListeners));\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/NullSampledStatisticsImpl.java",
    "content": "package org.quartz.core;\n\npublic class NullSampledStatisticsImpl implements SampledStatistics {\n    public long getJobsCompletedMostRecentSample() {\n        return 0;\n    }\n\n    public long getJobsExecutingMostRecentSample() {\n        return 0;\n    }\n\n    public long getJobsScheduledMostRecentSample() {\n        return 0;\n    }\n\n    public void shutdown() {\n        // nothing to do\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/QuartzScheduler.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.core;\n\nimport java.io.InputStream;\nimport java.lang.management.ManagementFactory;\nimport java.rmi.RemoteException;\nimport java.rmi.registry.LocateRegistry;\nimport java.rmi.registry.Registry;\nimport java.rmi.server.UnicastRemoteObject;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.Map.Entry;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport org.quartz.Calendar;\nimport org.quartz.InterruptableJob;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.JobListener;\nimport org.quartz.ListenerManager;\nimport org.quartz.Matcher;\nimport org.quartz.ObjectAlreadyExistsException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerListener;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport static org.quartz.TriggerBuilder.*;\nimport org.quartz.TriggerKey;\nimport org.quartz.TriggerListener;\nimport org.quartz.UnableToInterruptJobException;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.core.jmx.QuartzSchedulerMBean;\nimport org.quartz.impl.SchedulerRepository;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.listeners.SchedulerListenerSupport;\nimport org.quartz.simpl.PropertySettingJobFactory;\nimport org.quartz.spi.JobFactory;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.quartz.spi.SchedulerSignaler;\nimport org.quartz.spi.ThreadExecutor;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is the heart of Quartz, an indirect implementation of the <code>{@link org.quartz.Scheduler}</code>\n * interface, containing methods to schedule <code>{@link org.quartz.Job}</code>s,\n * register <code>{@link org.quartz.JobListener}</code> instances, etc.\n * </p>\n * \n * @see org.quartz.Scheduler\n * @see org.quartz.core.QuartzSchedulerThread\n * @see org.quartz.spi.JobStore\n * @see org.quartz.spi.ThreadPool\n * \n * @author James House\n */\npublic class QuartzScheduler implements RemotableQuartzScheduler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private static String VERSION_MAJOR = \"UNKNOWN\";\n    private static String VERSION_MINOR = \"UNKNOWN\";\n    private static String VERSION_ITERATION = \"UNKNOWN\";\n\n    static {\n        Properties props = new Properties();\n        try (InputStream is = QuartzScheduler.class.getResourceAsStream(\"quartz-build.properties\")) {\n            if (is != null) {\n                props.load(is);\n                String version = props.getProperty(\"version\");\n                if (version != null) {\n                    String[] versionComponents = version.split(\"\\\\.\");\n                    VERSION_MAJOR = versionComponents[0];\n                    VERSION_MINOR = versionComponents[1];\n                    if (versionComponents.length > 2)\n                        VERSION_ITERATION = versionComponents[2];\n                    else\n                        VERSION_ITERATION = \"0\";\n                } else {\n                    (LoggerFactory.getLogger(QuartzScheduler.class)).error(\n                            \"Can't parse Quartz version from quartz-build.properties\");\n                }\n            }\n        } catch (Exception e) {\n            (LoggerFactory.getLogger(QuartzScheduler.class)).error(\n                    \"Error loading version info from quartz-build.properties.\", e);\n        }\n    }\n    \n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final QuartzSchedulerResources resources;\n\n    private final QuartzSchedulerThread schedThread;\n\n    private ThreadGroup threadGroup;\n\n    private final SchedulerContext context = new SchedulerContext();\n\n    private final ListenerManager listenerManager = new ListenerManagerImpl();\n    \n    private final HashMap<String, JobListener> internalJobListeners = new HashMap<>(10);\n\n    private final HashMap<String, TriggerListener> internalTriggerListeners = new HashMap<>(10);\n\n    private final ArrayList<SchedulerListener> internalSchedulerListeners = new ArrayList<>(10);\n\n    private JobFactory jobFactory = new PropertySettingJobFactory();\n    \n    ExecutingJobsManager jobMgr = null;\n\n    ErrorLogger errLogger = null;\n\n    private final SchedulerSignaler signaler;\n\n    private final Random random = new Random();\n\n    private final ArrayList<Object> holdToPreventGC = new ArrayList<>(5);\n\n    private boolean signalOnSchedulingChange = true;\n\n    private volatile boolean closed = false;\n    private volatile boolean shuttingDown = false;\n    private boolean boundRemotely = false;\n\n    private QuartzSchedulerMBean jmxBean = null;\n    \n    private Date initialStart = null;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    // private static final Map<String, ManagementServer> MGMT_SVR_BY_BIND = new\n    // HashMap<String, ManagementServer>();\n    // private String registeredManagementServerBind;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>QuartzScheduler</code> with the given configuration\n     * properties.\n     * </p>\n     * \n     * @see QuartzSchedulerResources\n     */\n    public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)\n        throws SchedulerException {\n        this.resources = resources;\n        if (resources.getJobStore() instanceof JobListener) {\n            addInternalJobListener((JobListener)resources.getJobStore());\n        }\n\n        this.schedThread = new QuartzSchedulerThread(this, resources);\n        ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();\n        schedThreadExecutor.execute(this.schedThread);\n        if (idleWaitTime > 0) {\n            this.schedThread.setIdleWaitTime(idleWaitTime);\n        }\n\n        jobMgr = new ExecutingJobsManager();\n        addInternalJobListener(jobMgr);\n        errLogger = new ErrorLogger();\n        addInternalSchedulerListener(errLogger);\n\n        signaler = new SchedulerSignalerImpl(this, this.schedThread);\n\n        getLog().info(\"Quartz Scheduler v{} created.\", getVersion());\n    }\n\n    public void initialize() throws SchedulerException {\n        \n        try {\n            bind();\n        } catch (Exception re) {\n            throw new SchedulerException(\n                    \"Unable to bind scheduler to RMI Registry.\", re);\n        }\n        \n        if (resources.getJMXExport()) {\n            try {\n                registerJMX();\n            } catch (Exception e) {\n                throw new SchedulerException(\n                        \"Unable to register scheduler with MBeanServer.\", e);\n            }\n        }\n\n        // ManagementRESTServiceConfiguration managementRESTServiceConfiguration\n        // = resources.getManagementRESTServiceConfiguration();\n        //\n        // if (managementRESTServiceConfiguration != null &&\n        // managementRESTServiceConfiguration.isEnabled()) {\n        // try {\n        // /**\n        // * ManagementServer will only be instantiated and started if one\n        // * isn't already running on the configured port for this class\n        // * loader space.\n        // */\n        // synchronized (QuartzScheduler.class) {\n        // if\n        // (!MGMT_SVR_BY_BIND.containsKey(managementRESTServiceConfiguration.getBind()))\n        // {\n        // Class<?> managementServerImplClass =\n        // Class.forName(\"org.quartz.management.ManagementServerImpl\");\n        // Class<?> managementRESTServiceConfigurationClass[] = new Class[] {\n        // managementRESTServiceConfiguration.getClass() };\n        // Constructor<?> managementRESTServiceConfigurationConstructor =\n        // managementServerImplClass\n        // .getConstructor(managementRESTServiceConfigurationClass);\n        // Object arglist[] = new Object[] { managementRESTServiceConfiguration\n        // };\n        // ManagementServer embeddedRESTServer = ((ManagementServer)\n        // managementRESTServiceConfigurationConstructor.newInstance(arglist));\n        // embeddedRESTServer.start();\n        // MGMT_SVR_BY_BIND.put(managementRESTServiceConfiguration.getBind(),\n        // embeddedRESTServer);\n        // }\n        // registeredManagementServerBind =\n        // managementRESTServiceConfiguration.getBind();\n        // ManagementServer embeddedRESTServer =\n        // MGMT_SVR_BY_BIND.get(registeredManagementServerBind);\n        // embeddedRESTServer.register(this);\n        // }\n        // } catch (Exception e) {\n        // throw new\n        // SchedulerException(\"Unable to start the scheduler management REST service\",\n        // e);\n        // }\n        // }\n\n\n        getLog().info(\"Scheduler meta-data: {}\", new SchedulerMetaData(getSchedulerName(),\n                getSchedulerInstanceId(), getClass(), boundRemotely, runningSince() != null,\n                isInStandbyMode(), isShutdown(), runningSince(),\n                numJobsExecuted(), getJobStoreClass(),\n                supportsPersistence(), isClustered(), getThreadPoolClass(),\n                getThreadPoolSize(), getVersion()));\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public String getVersion() {\n        return getVersionMajor() + \".\" + getVersionMinor() + \".\"\n                + getVersionIteration();\n    }\n\n    public static String getVersionMajor() {\n        return VERSION_MAJOR;\n    }\n    \n    public static String getVersionMinor() {\n        return VERSION_MINOR;\n    }\n\n    public static String getVersionIteration() {\n        return VERSION_ITERATION;\n    }\n\n    public SchedulerSignaler getSchedulerSignaler() {\n        return signaler;\n    }\n\n    public Logger getLog() {\n        return log;\n    }\n    \n    /**\n     * Register the scheduler in the local MBeanServer.\n     */\n    private void registerJMX() throws Exception {\n        String jmxObjectName = resources.getJMXObjectName();\n        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();\n        jmxBean = new QuartzSchedulerMBeanImpl(this);\n        mbs.registerMBean(jmxBean, new ObjectName(jmxObjectName));\n    }\n\n    /**\n     * Unregister the scheduler from the local MBeanServer.\n     */\n    private void unregisterJMX() throws Exception {\n        String jmxObjectName = resources.getJMXObjectName();\n        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();\n        mbs.unregisterMBean(new ObjectName(jmxObjectName));\n        jmxBean.setSampledStatisticsEnabled(false);\n        getLog().info(\"Scheduler unregistered from name '{}' in the local MBeanServer.\", jmxObjectName);\n    }\n\n    /**\n     * <p>\n     * Bind the scheduler to an RMI registry.\n     * </p>\n     */\n    private void bind() throws RemoteException {\n        String host = resources.getRMIRegistryHost();\n        // don't export if we're not configured to do so...\n        if (host == null || host.isEmpty()) {\n            return;\n        }\n\n        RemotableQuartzScheduler exportable;\n\n        if(resources.getRMIServerPort() > 0) {\n            exportable = (RemotableQuartzScheduler) UnicastRemoteObject\n                .exportObject(this, resources.getRMIServerPort());\n        } else {\n            exportable = (RemotableQuartzScheduler) UnicastRemoteObject\n                .exportObject(this, 1099);\n        }\n\n        Registry registry;\n\n        if (resources.getRMICreateRegistryStrategy().equals(\n                QuartzSchedulerResources.CREATE_REGISTRY_AS_NEEDED)) {\n            try {\n                // First try to get an existing one, instead of creating it,\n                // since if\n                // we're in a web-app being 'hot' re-deployed, then the JVM\n                // still\n                // has the registry that we created above the first time...\n                registry = LocateRegistry.getRegistry(resources\n                        .getRMIRegistryPort());\n                registry.list();\n            } catch (Exception e) {\n                registry = LocateRegistry.createRegistry(resources\n                        .getRMIRegistryPort());\n            }\n        } else if (resources.getRMICreateRegistryStrategy().equals(\n                QuartzSchedulerResources.CREATE_REGISTRY_ALWAYS)) {\n            try {\n                registry = LocateRegistry.createRegistry(resources\n                        .getRMIRegistryPort());\n            } catch (Exception e) {\n                // Fall back to an existing one, instead of creating it, since\n                // if\n                // we're in a web-app being 'hot' re-deployed, then the JVM\n                // still\n                // has the registry that we created above the first time...\n                registry = LocateRegistry.getRegistry(resources\n                        .getRMIRegistryPort());\n            }\n        } else {\n            registry = LocateRegistry.getRegistry(resources\n                    .getRMIRegistryHost(), resources.getRMIRegistryPort());\n        }\n\n        String bindName = resources.getRMIBindName();\n        \n        registry.rebind(bindName, exportable);\n        \n        boundRemotely = true;\n\n        getLog().info(\"Scheduler bound to RMI registry under name '{}'\", bindName);\n    }\n\n    /**\n     * <p>\n     * Un-bind the scheduler from an RMI registry.\n     * </p>\n     */\n    private void unBind() throws RemoteException {\n        String host = resources.getRMIRegistryHost();\n        // don't un-export if we're not configured to do so...\n        if (host == null || host.isEmpty()) {\n            return;\n        }\n\n        Registry registry = LocateRegistry.getRegistry(resources\n                .getRMIRegistryHost(), resources.getRMIRegistryPort());\n\n        String bindName = resources.getRMIBindName();\n        \n        try {\n            registry.unbind(bindName);\n            UnicastRemoteObject.unexportObject(this, true);\n        } catch (java.rmi.NotBoundException nbe) {\n        }\n\n        getLog().info(\"Scheduler un-bound from name '{}' in RMI registry\", bindName);\n    }\n\n    /**\n     * <p>\n     * Returns the name of the <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public String getSchedulerName() {\n        return resources.getName();\n    }\n\n    /**\n     * <p>\n     * Returns the instance Id of the <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public String getSchedulerInstanceId() {\n        return resources.getInstanceId();\n    }\n\n    /**\n     * <p>\n     * Returns the name of the thread group for Quartz's main threads.\n     * </p>\n     */\n    public ThreadGroup getSchedulerThreadGroup() {\n        if (threadGroup == null) {\n            threadGroup = new ThreadGroup(\"QuartzScheduler:\"\n                    + getSchedulerName());\n            if (resources.getMakeSchedulerThreadDaemon()) {\n                threadGroup.setDaemon(true);\n            }\n        }\n\n        return threadGroup;\n    }\n\n    public void addNoGCObject(Object obj) {\n        holdToPreventGC.add(obj);\n    }\n\n    public boolean removeNoGCObject(Object obj) {\n        return holdToPreventGC.remove(obj);\n    }\n\n    /**\n     * <p>\n     * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.\n     * </p>\n     */\n    public SchedulerContext getSchedulerContext() throws SchedulerException {\n        return context;\n    }\n\n    public boolean isSignalOnSchedulingChange() {\n        return signalOnSchedulingChange;\n    }\n\n    public void setSignalOnSchedulingChange(boolean signalOnSchedulingChange) {\n        this.signalOnSchedulingChange = signalOnSchedulingChange;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduler State Management Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Starts the <code>QuartzScheduler</code>'s threads that fire <code>{@link org.quartz.Trigger}s</code>.\n     * </p>\n     * \n     * <p>\n     * All <code>{@link org.quartz.Trigger}s</code> that have misfired will\n     * be passed to the appropriate TriggerListener(s).\n     * </p>\n     */\n    public void start() throws SchedulerException {\n\n        if (shuttingDown|| closed) {\n            throw new SchedulerException(\n                    \"The Scheduler cannot be restarted after shutdown() has been called.\");\n        }\n\n        // QTZ-212 : calling new schedulerStarting() method on the listeners\n        // right after entering start()\n        notifySchedulerListenersStarting();\n\n        if (initialStart == null) {\n            initialStart = new Date();\n            this.resources.getJobStore().schedulerStarted();            \n            startPlugins();\n        } else {\n            resources.getJobStore().schedulerResumed();\n        }\n\n        schedThread.togglePause(false);\n\n        getLog().info(\"Scheduler {} started.\", resources.getUniqueIdentifier());\n        \n        notifySchedulerListenersStarted();\n    }\n\n    public void startDelayed(final int seconds) throws SchedulerException\n    {\n        if (shuttingDown || closed) {\n            throw new SchedulerException(\n                    \"The Scheduler cannot be restarted after shutdown() has been called.\");\n        }\n\n        Thread t = new Thread(() -> {\n            try { Thread.sleep(seconds * 1000L); }\n            catch(InterruptedException ignore) {}\n            try { start(); }\n            catch(SchedulerException se) {\n                getLog().error(\"Unable to start scheduler after startup delay.\", se);\n            }\n        });\n        t.start();\n    }\n\n    /**\n     * <p>\n     * Temporarily halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>.\n     * </p>\n     * \n     * <p>\n     * The scheduler is not destroyed, and can be re-started at any time.\n     * </p>\n     */\n    public void standby() {\n        resources.getJobStore().schedulerPaused();\n        schedThread.togglePause(true);\n        getLog().info(\"Scheduler {} paused.\", resources.getUniqueIdentifier());\n        notifySchedulerListenersInStandbyMode();        \n    }\n\n    /**\n     * <p>\n     * Reports whether the <code>Scheduler</code> is paused.\n     * </p>\n     */\n    public boolean isInStandbyMode() {\n        return schedThread.isPaused();\n    }\n\n    public Date runningSince() {\n        if(initialStart == null)\n            return null;\n        return new Date(initialStart.getTime());\n    }\n\n    public int numJobsExecuted() {\n        return jobMgr.getNumJobsFired();\n    }\n\n    public Class<?> getJobStoreClass() {\n        return resources.getJobStore().getClass();\n    }\n\n    public boolean supportsPersistence() {\n        return resources.getJobStore().supportsPersistence();\n    }\n\n    public boolean isClustered() {\n        return resources.getJobStore().isClustered();\n    }\n\n    public Class<?> getThreadPoolClass() {\n        return resources.getThreadPool().getClass();\n    }\n\n    public int getThreadPoolSize() {\n        return resources.getThreadPool().getPoolSize();\n    }\n\n    /**\n     * <p>\n     * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,\n     * and cleans up all resources associated with the QuartzScheduler.\n     * Equivalent to <code>shutdown(false)</code>.\n     * </p>\n     * \n     * <p>\n     * The scheduler cannot be re-started.\n     * </p>\n     */\n    public void shutdown() {\n        shutdown(false);\n    }\n\n    /**\n     * <p>\n     * Halts the <code>QuartzScheduler</code>'s firing of <code>{@link org.quartz.Trigger}s</code>,\n     * and cleans up all resources associated with the QuartzScheduler.\n     * </p>\n     * \n     * <p>\n     * The scheduler cannot be re-started.\n     * </p>\n     * \n     * @param waitForJobsToComplete\n     *          if <code>true</code> the scheduler will not allow this method\n     *          to return until all currently executing jobs have completed.\n     */\n    public void shutdown(boolean waitForJobsToComplete) {\n        \n        if(shuttingDown || closed) {\n            return;\n        }\n        \n        shuttingDown = true;\n\n        getLog().info(\"Scheduler {} shutting down.\", resources.getUniqueIdentifier());\n        // boolean removeMgmtSvr = false;\n        // if (registeredManagementServerBind != null) {\n        // ManagementServer standaloneRestServer =\n        // MGMT_SVR_BY_BIND.get(registeredManagementServerBind);\n        //\n        // try {\n        // standaloneRestServer.unregister(this);\n        //\n        // if (!standaloneRestServer.hasRegistered()) {\n        // removeMgmtSvr = true;\n        // standaloneRestServer.stop();\n        // }\n        // } catch (Exception e) {\n        // getLog().warn(\"Failed to shutdown the ManagementRESTService\", e);\n        // } finally {\n        // if (removeMgmtSvr) {\n        // MGMT_SVR_BY_BIND.remove(registeredManagementServerBind);\n        // }\n        //\n        // registeredManagementServerBind = null;\n        // }\n        // }\n\n        standby();\n\n        schedThread.halt(waitForJobsToComplete);\n        \n        notifySchedulerListenersShuttingdown();\n        \n        if( (resources.isInterruptJobsOnShutdown() && !waitForJobsToComplete) || \n                (resources.isInterruptJobsOnShutdownWithWait() && waitForJobsToComplete)) {\n            List<JobExecutionContext> jobs = getCurrentlyExecutingJobs();\n            for(JobExecutionContext job: jobs) {\n                if(job.getJobInstance() instanceof InterruptableJob)\n                    try {\n                        ((InterruptableJob)job.getJobInstance()).interrupt();\n                    } catch (Throwable e) {\n                        // do nothing, this was just a courtesy effort\n                        getLog().warn(\"Encountered error when interrupting job {} during shutdown: {}\", job.getJobDetail().getKey(), e.getMessage(), e);\n                    }\n            }\n        }\n        \n        resources.getThreadPool().shutdown(waitForJobsToComplete);\n        \n        closed = true;\n\n        if (resources.getJMXExport()) {\n            try {\n                unregisterJMX();\n            } catch (Exception e) {\n            }\n        }\n\n        if(boundRemotely) {\n            try {\n                unBind();\n            } catch (RemoteException re) {\n            }\n        }\n        \n        shutdownPlugins();\n\n        resources.getJobStore().shutdown();\n\n        notifySchedulerListenersShutdown();\n\n        SchedulerRepository.getInstance().remove(resources.getName());\n\n        holdToPreventGC.clear();\n\n        getLog().info(\"Scheduler {} shutdown complete.\", resources.getUniqueIdentifier());\n    }\n\n    /**\n     * <p>\n     * Reports whether the <code>Scheduler</code> has been shutdown.\n     * </p>\n     */\n    public boolean isShutdown() {\n        return closed;\n    }\n\n    public boolean isShuttingDown() {\n        return shuttingDown;\n    }\n\n    public boolean isStarted() {\n        return !shuttingDown && !closed && !isInStandbyMode() && initialStart != null;\n    }\n    \n    public void validateState() throws SchedulerException {\n        if (isShutdown()) {\n            throw new SchedulerException(\"The Scheduler has been shutdown.\");\n        }\n\n        // other conditions to check (?)\n    }\n\n    /**\n     * <p>\n     * Return a list of <code>JobExecutionContext</code> objects that\n     * represent all currently executing Jobs in this Scheduler instance.\n     * </p>\n     * \n     * <p>\n     * This method is not cluster aware.  That is, it will only return Jobs\n     * currently executing in this Scheduler instance, not across the entire\n     * cluster.\n     * </p>\n     * \n     * <p>\n     * Note that the list returned is an 'instantaneous' snap-shot, and that as\n     * soon as it's returned, the true list of executing jobs may be different.\n     * </p>\n     */\n    public List<JobExecutionContext> getCurrentlyExecutingJobs() {\n        return jobMgr.getExecutingJobs();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduling-related Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Add the <code>{@link org.quartz.Job}</code> identified by the given\n     * <code>{@link org.quartz.JobDetail}</code> to the Scheduler, and\n     * associate the given <code>{@link org.quartz.Trigger}</code> with it.\n     * </p>\n     * \n     * <p>\n     * If the given Trigger does not reference any <code>Job</code>, then it\n     * will be set to reference the Job passed with it into this method.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if the Job or Trigger cannot be added to the Scheduler, or\n     *           there is an internal Scheduler error.\n     */\n    public Date scheduleJob(JobDetail jobDetail,\n            Trigger trigger) throws SchedulerException {\n        validateState();\n\n        if (jobDetail == null) {\n            throw new SchedulerException(\"JobDetail cannot be null\");\n        }\n        \n        if (trigger == null) {\n            throw new SchedulerException(\"Trigger cannot be null\");\n        }\n        \n        if (jobDetail.getKey() == null) {\n            throw new SchedulerException(\"Job's key cannot be null\");\n        }\n\n        if (jobDetail.getJobClass() == null) {\n            throw new SchedulerException(\"Job's class cannot be null\");\n        }\n        \n        OperableTrigger trig = (OperableTrigger)trigger;\n\n        if (trigger.getJobKey() == null) {\n            trig.setJobKey(jobDetail.getKey());\n        } else if (!trigger.getJobKey().equals(jobDetail.getKey())) {\n            throw new SchedulerException(\n                \"Trigger does not reference given job!\");\n        }\n\n        trig.validate();\n\n        Calendar cal = null;\n        if (trigger.getCalendarName() != null) {\n            cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName());\n        }\n        Date ft = trig.computeFirstFireTime(cal);\n\n        if (ft == null) {\n            throw new SchedulerException(\n                    \"Based on configured schedule, the given trigger '\" + trigger.getKey() + \"' will never fire.\");\n        }\n\n        resources.getJobStore().storeJobAndTrigger(jobDetail, trig);\n        notifySchedulerListenersJobAdded(jobDetail);\n        notifySchedulerThread(trigger.getNextFireTime().getTime());\n        notifySchedulerListenersScheduled(trigger);\n\n        return ft;\n    }\n\n    /**\n     * <p>\n     * Schedule the given <code>{@link org.quartz.Trigger}</code> with the\n     * <code>Job</code> identified by the <code>Trigger</code>'s settings.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if the indicated Job does not exist, or the Trigger cannot be\n     *           added to the Scheduler, or there is an internal Scheduler\n     *           error.\n     */\n    public Date scheduleJob(Trigger trigger)\n        throws SchedulerException {\n        validateState();\n\n        if (trigger == null) {\n            throw new SchedulerException(\"Trigger cannot be null\");\n        }\n\n        OperableTrigger trig = (OperableTrigger)trigger;\n        \n        trig.validate();\n\n        Calendar cal = null;\n        if (trigger.getCalendarName() != null) {\n            cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName());\n            if(cal == null) {\n                throw new SchedulerException(\n                    \"Calendar not found: \" + trigger.getCalendarName());\n            }\n        }\n        Date ft = trig.computeFirstFireTime(cal);\n\n        if (ft == null) {\n            throw new SchedulerException(\n                    \"Based on configured schedule, the given trigger '\" + trigger.getKey() + \"' will never fire.\");\n        }\n\n        resources.getJobStore().storeTrigger(trig, false);\n        notifySchedulerThread(trigger.getNextFireTime().getTime());\n        notifySchedulerListenersScheduled(trigger);\n\n        return ft;\n    }\n\n    /**\n     * <p>\n     * Add the given <code>Job</code> to the Scheduler - with no associated\n     * <code>Trigger</code>. The <code>Job</code> will be 'dormant' until\n     * it is scheduled with a <code>Trigger</code>, or <code>Scheduler.triggerJob()</code>\n     * is called for it.\n     * </p>\n     * \n     * <p>\n     * The <code>Job</code> must by definition be 'durable', if it is not,\n     * SchedulerException will be thrown.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or if the Job is not\n     *           durable, or a Job with the same name already exists, and\n     *           <code>replace</code> is <code>false</code>.\n     */\n    public void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException {\n        addJob(jobDetail, replace, false);\n    }\n\n    public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException {\n        validateState();\n\n        if (!storeNonDurableWhileAwaitingScheduling && !jobDetail.isDurable()) {\n            throw new SchedulerException(\n                    \"Jobs added with no trigger must be durable.\");\n        }\n\n        resources.getJobStore().storeJob(jobDetail, replace);\n        notifySchedulerThread(0L);\n        notifySchedulerListenersJobAdded(jobDetail);\n    }\n\n    /**\n     * <p>\n     * Delete the identified <code>Job</code> from the Scheduler - and any\n     * associated <code>Trigger</code>s.\n     * </p>\n     * \n     * @return true if the Job was found and deleted.\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error.\n     */\n    public boolean deleteJob(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        boolean result = false;\n        \n        List<? extends Trigger> triggers = getTriggersOfJob(jobKey);\n        for (Trigger trigger : triggers) {\n            if (!unscheduleJob(trigger.getKey())) {\n                StringBuilder sb = new StringBuilder().append(\n                        \"Unable to unschedule trigger [\").append(\n                        trigger.getKey()).append(\"] while deleting job [\")\n                        .append(jobKey).append(\n                                \"]\");\n                throw new SchedulerException(sb.toString());\n            }\n            result = true;\n        }\n\n        result = resources.getJobStore().removeJob(jobKey) || result;\n        if (result) {\n            notifySchedulerThread(0L);\n            notifySchedulerListenersJobDeleted(jobKey);\n        }\n        return result;\n    }\n\n    public boolean deleteJobs(List<JobKey> jobKeys)  throws SchedulerException {\n        validateState();\n\n        boolean result;\n        \n        result = resources.getJobStore().removeJobs(jobKeys);\n        notifySchedulerThread(0L);\n        for(JobKey key: jobKeys)\n            notifySchedulerListenersJobDeleted(key);\n        return result;\n    }\n\n    public void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace)  throws SchedulerException  {\n        validateState();\n\n        // make sure all triggers refer to their associated job\n        for(Entry<JobDetail, Set<? extends Trigger>> e: triggersAndJobs.entrySet()) {\n            JobDetail job = e.getKey();\n            if(job == null) // there can be one of these (for adding a bulk set of triggers for preexisting jobs)\n                continue;\n            Set<? extends Trigger> triggers = e.getValue();\n            if(triggers == null) // this is possible because the job may be durable, and not yet be having triggers\n                continue;\n            for(Trigger trigger: triggers) {\n                OperableTrigger opt = (OperableTrigger)trigger;\n                opt.setJobKey(job.getKey());\n\n                opt.validate();\n\n                Calendar cal = null;\n                if (trigger.getCalendarName() != null) {\n                    cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName());\n                    if(cal == null) {\n                        throw new SchedulerException(\n                            \"Calendar '\" + trigger.getCalendarName() + \"' not found for trigger: \" + trigger.getKey());\n                    }\n                }\n                Date ft = opt.computeFirstFireTime(cal);\n\n                if (ft == null) {\n                    throw new SchedulerException(\n                            \"Based on configured schedule, the given trigger will never fire.\");\n                }                \n            }\n        }\n\n        resources.getJobStore().storeJobsAndTriggers(triggersAndJobs, replace);\n        notifySchedulerThread(0L);\n        for (JobDetail job : triggersAndJobs.keySet()) {\n          notifySchedulerListenersJobAdded(job);\n\n          Set<? extends Trigger> triggers = triggersAndJobs.get(job);\n          for (Trigger trigger : triggers) {\n            notifySchedulerListenersScheduled(trigger);\n          }\n        }\n    }\n\n    public void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob,\n            boolean replace) throws SchedulerException {\n        Map<JobDetail, Set<? extends Trigger>> triggersAndJobs = new HashMap<>();\n        triggersAndJobs.put(jobDetail, triggersForJob);\n        scheduleJobs(triggersAndJobs, replace);\n    }\n\n    public boolean unscheduleJobs(List<TriggerKey> triggerKeys) throws SchedulerException  {\n        validateState();\n\n        boolean result;\n        \n        result = resources.getJobStore().removeTriggers(triggerKeys);\n        notifySchedulerThread(0L);\n        for(TriggerKey key: triggerKeys)\n            notifySchedulerListenersUnscheduled(key);\n        return result;\n    }\n    \n    /**\n     * <p>\n     * Remove the indicated <code>{@link org.quartz.Trigger}</code> from the\n     * scheduler.\n     * </p>\n     */\n    public boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        if (resources.getJobStore().removeTrigger(triggerKey)) {\n            notifySchedulerThread(0L);\n            notifySchedulerListenersUnscheduled(triggerKey);\n        } else {\n            return false;\n        }\n\n        return true;\n    }\n\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given name, and store the new given one - which must be associated\n     * with the same job.\n     * </p>\n     * @param newTrigger\n     *          The new <code>Trigger</code> to be stored.\n     * \n     * @return <code>null</code> if a <code>Trigger</code> with the given\n     *         name and group was not found and removed from the store, otherwise\n     *         the first fire time of the newly scheduled trigger.\n     */\n    public Date rescheduleJob(TriggerKey triggerKey,\n            Trigger newTrigger) throws SchedulerException {\n        validateState();\n\n        if (triggerKey == null) {\n            throw new IllegalArgumentException(\"triggerKey cannot be null\");\n        }\n        if (newTrigger == null) {\n            throw new IllegalArgumentException(\"newTrigger cannot be null\");\n        }\n\n        OperableTrigger trig = (OperableTrigger)newTrigger;\n        Trigger oldTrigger = getTrigger(triggerKey);\n        if (oldTrigger == null) {\n            return null;\n        } else {\n            trig.setJobKey(oldTrigger.getJobKey());\n        }\n        trig.validate();\n\n        Calendar cal = null;\n        if (newTrigger.getCalendarName() != null) {\n            cal = resources.getJobStore().retrieveCalendar(\n                    newTrigger.getCalendarName());\n        }\n        Date ft = trig.computeFirstFireTime(cal);\n\n        if (ft == null) {\n            throw new SchedulerException(\n                    \"Based on configured schedule, the given trigger will never fire.\");\n        }\n        \n        if (resources.getJobStore().replaceTrigger(triggerKey, trig)) {\n            notifySchedulerThread(newTrigger.getNextFireTime().getTime());\n            notifySchedulerListenersUnscheduled(triggerKey);\n            notifySchedulerListenersScheduled(newTrigger);\n        } else {\n            return null;\n        }\n\n        return ft;\n        \n    }\n    \n    \n    private String newTriggerId() {\n        long r = random.nextLong();\n        if (r < 0) {\n            r = -r;\n        }\n        return \"MT_\"\n                + Long.toString(r, 30 + (int) (System.currentTimeMillis() % 7));\n    }\n\n    /**\n     * <p>\n     * Trigger the identified <code>{@link org.quartz.Job}</code> (execute it\n     * now) - with a non-volatile trigger.\n     * </p>\n     */\n    @SuppressWarnings(\"deprecation\")\n    public void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException {\n        validateState();\n\n        OperableTrigger trig = (OperableTrigger) newTrigger().withIdentity(newTriggerId(), Scheduler.DEFAULT_GROUP).forJob(jobKey).build();\n        trig.computeFirstFireTime(null);\n        if(data != null) {\n            trig.setJobDataMap(data);\n        }\n\n        boolean collision = true;\n        while (collision) {\n            try {\n                resources.getJobStore().storeTrigger(trig, false);\n                collision = false;\n            } catch (ObjectAlreadyExistsException oaee) {\n                trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP));\n            }\n        }\n\n        notifySchedulerThread(trig.getNextFireTime().getTime());\n        notifySchedulerListenersScheduled(trig);\n    }\n\n    /**\n     * <p>\n     * Store and schedule the identified <code>{@link org.quartz.spi.OperableTrigger}</code>\n     * </p>\n     */\n    public void triggerJob(OperableTrigger trig) throws SchedulerException {\n        validateState();\n\n        trig.computeFirstFireTime(null);\n\n        boolean collision = true;\n        while (collision) {\n            try {\n                resources.getJobStore().storeTrigger(trig, false);\n                collision = false;\n            } catch (ObjectAlreadyExistsException oaee) {\n                trig.setKey(new TriggerKey(newTriggerId(), Scheduler.DEFAULT_GROUP));\n            }\n        }\n\n        notifySchedulerThread(trig.getNextFireTime().getTime());\n        notifySchedulerListenersScheduled(trig);\n    }\n    \n    /**\n     * <p>\n     * Pause the <code>{@link Trigger}</code> with the given name.\n     * </p>\n     *  \n     */\n    public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().pauseTrigger(triggerKey);\n        notifySchedulerThread(0L);\n        notifySchedulerListenersPausedTrigger(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Pause all of the <code>{@link Trigger}s</code> in the matching groups.\n     * </p>\n     *  \n     */\n    public void pauseTriggers(GroupMatcher<TriggerKey> matcher)\n        throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n\n        Collection<String> pausedGroups = resources.getJobStore().pauseTriggers(matcher);\n        notifySchedulerThread(0L);\n        for (String pausedGroup : pausedGroups) {\n            notifySchedulerListenersPausedTriggers(pausedGroup);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause the <code>{@link org.quartz.JobDetail}</code> with the given\n     * name - by pausing all of its current <code>Trigger</code>s.\n     * </p>\n     *  \n     */\n    public void pauseJob(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().pauseJob(jobKey);\n        notifySchedulerThread(0L);\n        notifySchedulerListenersPausedJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the\n     * matching groups - by pausing all of their <code>Trigger</code>s.\n     * </p>\n     *  \n     */\n    public void pauseJobs(GroupMatcher<JobKey> groupMatcher)\n        throws SchedulerException {\n        validateState();\n\n        if(groupMatcher == null) {\n            groupMatcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n        \n        Collection<String> pausedGroups = resources.getJobStore().pauseJobs(groupMatcher);\n        notifySchedulerThread(0L);\n        for (String pausedGroup : pausedGroups) {\n            notifySchedulerListenersPausedJobs(pausedGroup);\n        }\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link Trigger}</code> with the given\n     * name.\n     * </p>\n     * \n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *  \n     */\n    public void resumeTrigger(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().resumeTrigger(triggerKey);\n        notifySchedulerThread(0L);\n        notifySchedulerListenersResumedTrigger(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the\n     * matching groups.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *  \n     */\n    public void resumeTriggers(GroupMatcher<TriggerKey> matcher)\n        throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n\n        Collection<String> pausedGroups = resources.getJobStore().resumeTriggers(matcher);\n        notifySchedulerThread(0L);\n        for (String pausedGroup : pausedGroups) {\n            notifySchedulerListenersResumedTriggers(pausedGroup);\n        }\n    }\n\n    public Set<String> getPausedTriggerGroups() throws SchedulerException {\n        return resources.getJobStore().getPausedTriggerGroups();\n    }\n    \n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with\n     * the given name.\n     * </p>\n     * \n     * <p>\n     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one\n     * or more fire-times, then the <code>Trigger</code>'s misfire\n     * instruction will be applied.\n     * </p>\n     *  \n     */\n    public void resumeJob(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().resumeJob(jobKey);\n        notifySchedulerThread(0L);\n        notifySchedulerListenersResumedJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>\n     * in the matching groups.\n     * </p>\n     * \n     * <p>\n     * If any of the <code>Job</code> s had <code>Trigger</code> s that\n     * missed one or more fire-times, then the <code>Trigger</code>'s\n     * misfire instruction will be applied.\n     * </p>\n     *  \n     */\n    public void resumeJobs(GroupMatcher<JobKey> matcher)\n        throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n        \n        Collection<String> resumedGroups = resources.getJobStore().resumeJobs(matcher);\n        notifySchedulerThread(0L);\n        for (String pausedGroup : resumedGroups) {\n            notifySchedulerListenersResumedJobs(pausedGroup);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause all triggers - equivalent of calling <code>pauseTriggers(GroupMatcher)</code>\n     * with a matcher matching all known groups.\n     * </p>\n     * \n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     * \n     * @see #resumeAll()\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     * @see #standby()\n     */\n    public void pauseAll() throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().pauseAll();\n        notifySchedulerThread(0L);\n        notifySchedulerListenersPausedTriggers(null);\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseAll()\n     */\n    public void resumeAll() throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().resumeAll();\n        notifySchedulerThread(0L);\n        notifySchedulerListenersResumedTrigger(null);\n    }\n\n    /**\n     * <p>\n     * Get the names of all known <code>{@link org.quartz.Job}</code> groups.\n     * </p>\n     */\n    public List<String> getJobGroupNames()\n        throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().getJobGroupNames();\n    }\n\n    /**\n     * <p>\n     * Get the names of all the <code>{@link org.quartz.Job}s</code> in the\n     * matching groups.\n     * </p>\n     */\n    public Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher)\n        throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n        \n        return resources.getJobStore().getJobKeys(matcher);\n    }\n\n    /**\n     * <p>\n     * Get all <code>{@link Trigger}</code> s that are associated with the\n     * identified <code>{@link org.quartz.JobDetail}</code>.\n     * </p>\n     */\n    public List<? extends Trigger> getTriggersOfJob(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().getTriggersForJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Get the names of all known <code>{@link org.quartz.Trigger}</code>\n     * groups.\n     * </p>\n     */\n    public List<String> getTriggerGroupNames()\n        throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().getTriggerGroupNames();\n    }\n\n    /**\n     * <p>\n     * Get the names of all the <code>{@link org.quartz.Trigger}s</code> in\n     * the matching groups.\n     * </p>\n     */\n    public Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher)\n        throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n        \n        return resources.getJobStore().getTriggerKeys(matcher);\n    }\n\n    /**\n     * <p>\n     * Get the <code>{@link JobDetail}</code> for the <code>Job</code>\n     * instance with the given name and group.\n     * </p>\n     */\n    public JobDetail getJobDetail(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().retrieveJob(jobKey);\n    }\n\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        validateState();\n\n        if(matcher == null) {\n            matcher = GroupMatcher.groupEquals(Scheduler.DEFAULT_GROUP);\n        }\n        return resources.getJobStore().getJobDetails(matcher);\n    }\n\n\n    /**\n     * <p>\n     * Get the <code>{@link Trigger}</code> instance with the given name and\n     * group.\n     * </p>\n     */\n    public Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().retrieveTrigger(triggerKey);\n    }\n\n    /**\n     * Determine whether a {@link Job} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param jobKey the identifier to check for\n     * @return true if a Job exists with the given identifier\n     * @throws SchedulerException \n     */\n    public boolean checkExists(JobKey jobKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().checkExists(jobKey);\n        \n    }\n   \n    /**\n     * Determine whether a {@link Trigger} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param triggerKey the identifier to check for\n     * @return true if a Trigger exists with the given identifier\n     * @throws SchedulerException \n     */\n    public boolean checkExists(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().checkExists(triggerKey);\n        \n    }\n    \n    /**\n     * Clears (deletes!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws SchedulerException\n     */\n    public void clear() throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().clearAllSchedulingData();\n        notifySchedulerListenersUnscheduled(null);\n    }\n    \n    \n    /**\n     * <p>\n     * Get the current state of the identified <code>{@link Trigger}</code>.\n     * </p>\nJ     *\n     * @see TriggerState\n     */\n    public TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().getTriggerState(triggerKey);\n    }\n\n\n    public void resetTriggerFromErrorState(TriggerKey triggerKey) throws SchedulerException  {\n        validateState();\n\n        resources.getJobStore().resetTriggerFromErrorState(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Add (register) the given <code>Calendar</code> to the Scheduler.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           if there is an internal Scheduler error, or a Calendar with\n     *           the same name already exists, and <code>replace</code> is\n     *           <code>false</code>.\n     */\n    public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException {\n        validateState();\n\n        resources.getJobStore().storeCalendar(calName, calendar, replace, updateTriggers);\n    }\n\n    /**\n     * <p>\n     * Delete the identified <code>Calendar</code> from the Scheduler.\n     * </p>\n     * \n     * @return true if the Calendar was found and deleted.\n     * @throws SchedulerException\n     *           if there is an internal Scheduler error.\n     */\n    public boolean deleteCalendar(String calName)\n        throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().removeCalendar(calName);\n    }\n\n    /**\n     * <p>\n     * Get the <code>{@link Calendar}</code> instance with the given name.\n     * </p>\n     */\n    public Calendar getCalendar(String calName)\n        throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().retrieveCalendar(calName);\n    }\n\n    /**\n     * <p>\n     * Get the names of all registered <code>{@link Calendar}s</code>.\n     * </p>\n     */\n    public List<String> getCalendarNames()\n        throws SchedulerException {\n        validateState();\n\n        return resources.getJobStore().getCalendarNames();\n    }\n\n    public ListenerManager getListenerManager() {\n        return listenerManager;\n    }\n    \n    /**\n     * <p>\n     * Add the given <code>{@link org.quartz.JobListener}</code> to the\n     * <code>Scheduler</code>'s <i>internal</i> list.\n     * </p>\n     */\n    public void addInternalJobListener(JobListener jobListener) {\n        if (jobListener.getName() == null\n                || jobListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"JobListener name cannot be empty.\");\n        }\n        \n        synchronized (internalJobListeners) {\n            internalJobListeners.put(jobListener.getName(), jobListener);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove the identified <code>{@link JobListener}</code> from the <code>Scheduler</code>'s\n     * list of <i>internal</i> listeners.\n     * </p>\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    public boolean removeInternalJobListener(String name) {\n        synchronized (internalJobListeners) {\n            return (internalJobListeners.remove(name) != null);\n        }\n    }\n    \n    /**\n     * <p>\n     * Get a List containing all of the <code>{@link org.quartz.JobListener}</code>s\n     * in the <code>Scheduler</code>'s <i>internal</i> list.\n     * </p>\n     */\n    public List<JobListener> getInternalJobListeners() {\n        synchronized (internalJobListeners) {\n            return java.util.Collections.unmodifiableList(new LinkedList<>(internalJobListeners.values()));\n        }\n    }\n\n    /**\n     * <p>\n     * Get the <i>internal</i> <code>{@link org.quartz.JobListener}</code>\n     * that has the given name.\n     * </p>\n     */\n    public JobListener getInternalJobListener(String name) {\n        synchronized (internalJobListeners) {\n            return internalJobListeners.get(name);\n        }\n    }\n    \n    /**\n     * <p>\n     * Add the given <code>{@link org.quartz.TriggerListener}</code> to the\n     * <code>Scheduler</code>'s <i>internal</i> list.\n     * </p>\n     */\n    public void addInternalTriggerListener(TriggerListener triggerListener) {\n        if (triggerListener.getName() == null\n                || triggerListener.getName().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"TriggerListener name cannot be empty.\");\n        }\n\n        synchronized (internalTriggerListeners) {\n            internalTriggerListeners.put(triggerListener.getName(), triggerListener);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove the identified <code>{@link TriggerListener}</code> from the <code>Scheduler</code>'s\n     * list of <i>internal</i> listeners.\n     * </p>\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    public boolean removeinternalTriggerListener(String name) {\n        synchronized (internalTriggerListeners) {\n            return (internalTriggerListeners.remove(name) != null);\n        }\n    }\n\n    /**\n     * <p>\n     * Get a list containing all of the <code>{@link org.quartz.TriggerListener}</code>s\n     * in the <code>Scheduler</code>'s <i>internal</i> list.\n     * </p>\n     */\n    public List<TriggerListener> getInternalTriggerListeners() {\n        synchronized (internalTriggerListeners) {\n            return java.util.Collections.unmodifiableList(new LinkedList<>(internalTriggerListeners.values()));\n        }\n    }\n\n    /**\n     * <p>\n     * Get the <i>internal</i> <code>{@link TriggerListener}</code> that\n     * has the given name.\n     * </p>\n     */\n    public TriggerListener getInternalTriggerListener(String name) {\n        synchronized (internalTriggerListeners) {\n            return internalTriggerListeners.get(name);\n        }\n    }\n\n    /**\n     * <p>\n     * Register the given <code>{@link SchedulerListener}</code> with the\n     * <code>Scheduler</code>'s list of internal listeners.\n     * </p>\n     */\n    public void addInternalSchedulerListener(SchedulerListener schedulerListener) {\n        synchronized (internalSchedulerListeners) {\n            internalSchedulerListeners.add(schedulerListener);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove the given <code>{@link SchedulerListener}</code> from the\n     * <code>Scheduler</code>'s list of internal listeners.\n     * </p>\n     * \n     * @return true if the identified listener was found in the list, and\n     *         removed.\n     */\n    public boolean removeInternalSchedulerListener(SchedulerListener schedulerListener) {\n        synchronized (internalSchedulerListeners) {\n            return internalSchedulerListeners.remove(schedulerListener);\n        }\n    }\n\n    /**\n     * <p>\n     * Get a List containing all of the <i>internal</i> <code>{@link SchedulerListener}</code>s\n     * registered with the <code>Scheduler</code>.\n     * </p>\n     */\n    public List<SchedulerListener> getInternalSchedulerListeners() {\n        synchronized (internalSchedulerListeners) {\n            return java.util.Collections.unmodifiableList(new ArrayList<>(internalSchedulerListeners));\n        }\n    }\n\n    protected void notifyJobStoreJobComplete(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) {\n        resources.getJobStore().triggeredJobComplete(trigger, detail, instCode);\n    }\n\n    protected void notifyJobStoreJobVetoed(OperableTrigger trigger, JobDetail detail, CompletedExecutionInstruction instCode) {\n        resources.getJobStore().triggeredJobComplete(trigger, detail, instCode);\n    }\n\n    protected void notifySchedulerThread(long candidateNewNextFireTime) {\n        if (isSignalOnSchedulingChange()) {\n            signaler.signalSchedulingChange(candidateNewNextFireTime);\n        }\n    }\n\n    private List<TriggerListener> buildTriggerListenerList()\n        throws SchedulerException {\n        List<TriggerListener> allListeners = new LinkedList<>();\n        allListeners.addAll(getListenerManager().getTriggerListeners());\n        allListeners.addAll(getInternalTriggerListeners());\n\n        return allListeners;\n    }\n\n    private List<JobListener> buildJobListenerList()\n        throws SchedulerException {\n        List<JobListener> allListeners = new LinkedList<>();\n        allListeners.addAll(getListenerManager().getJobListeners());\n        allListeners.addAll(getInternalJobListeners());\n\n        return allListeners;\n    }\n\n    private List<SchedulerListener> buildSchedulerListenerList() {\n        List<SchedulerListener> allListeners = new LinkedList<>();\n        allListeners.addAll(getListenerManager().getSchedulerListeners());\n        allListeners.addAll(getInternalSchedulerListeners());\n    \n        return allListeners;\n    }\n    \n    private boolean matchJobListener(JobListener listener, JobKey key) {\n        List<Matcher<JobKey>> matchers = getListenerManager().getJobListenerMatchers(listener.getName());\n        if(matchers == null)\n            return true;\n        for(Matcher<JobKey> matcher: matchers) {\n            if(matcher.isMatch(key))\n                return true;\n        }\n        return false;\n    }\n\n    private boolean matchTriggerListener(TriggerListener listener, TriggerKey key) {\n        List<Matcher<TriggerKey>> matchers = getListenerManager().getTriggerListenerMatchers(listener.getName());\n        if(matchers == null)\n            return true;\n        for(Matcher<TriggerKey> matcher: matchers) {\n            if(matcher.isMatch(key))\n                return true;\n        }\n        return false;\n    }\n\n    public boolean notifyTriggerListenersFired(JobExecutionContext jec)\n        throws SchedulerException {\n\n        boolean vetoedExecution = false;\n        \n        // build a list of all trigger listeners that are to be notified...\n        List<TriggerListener> triggerListeners = buildTriggerListenerList();\n\n        // notify all trigger listeners in the list\n        for(TriggerListener tl: triggerListeners) {\n            try {\n                if(!matchTriggerListener(tl, jec.getTrigger().getKey()))\n                    continue;\n                tl.triggerFired(jec.getTrigger(), jec);\n                \n                if(tl.vetoJobExecution(jec.getTrigger(), jec)) {\n                    vetoedExecution = true;\n                }\n            } catch (Exception e) {\n                throw new JobExecutionProcessException(tl, jec, e);\n            }\n        }\n        \n        return vetoedExecution;\n    }\n    \n\n    public void notifyTriggerListenersMisfired(Trigger trigger)\n        throws SchedulerException {\n        // build a list of all trigger listeners that are to be notified...\n        List<TriggerListener> triggerListeners = buildTriggerListenerList();\n\n        // notify all trigger listeners in the list\n        for(TriggerListener tl: triggerListeners) {\n            try {\n                if(!matchTriggerListener(tl, trigger.getKey()))\n                    continue;\n                tl.triggerMisfired(trigger);\n            } catch (Exception e) {\n                throw new SchedulerException(\n                        \"TriggerListener '\" + tl.getName()\n                                + \"' threw exception: \" + e.getMessage(), e);\n            }\n        }\n    }    \n\n    public void notifyTriggerListenersComplete(JobExecutionContext jec,\n            CompletedExecutionInstruction instCode) throws SchedulerException {\n        // build a list of all trigger listeners that are to be notified...\n        List<TriggerListener> triggerListeners = buildTriggerListenerList();\n\n        // notify all trigger listeners in the list\n        for(TriggerListener tl: triggerListeners) {\n            try {\n                if(!matchTriggerListener(tl, jec.getTrigger().getKey()))\n                    continue;\n                tl.triggerComplete(jec.getTrigger(), jec, instCode);\n            } catch (Exception e) {\n                throw new JobExecutionProcessException(tl, jec, e);\n            }\n        }\n    }\n\n    public void notifyJobListenersToBeExecuted(JobExecutionContext jec)\n        throws SchedulerException {\n        // build a list of all job listeners that are to be notified...\n        List<JobListener> jobListeners = buildJobListenerList();\n\n        // notify all job listeners\n        for(JobListener jl: jobListeners) {\n            try {\n                if(!matchJobListener(jl, jec.getJobDetail().getKey()))\n                    continue;\n                jl.jobToBeExecuted(jec);\n            } catch (Exception e) {\n                throw new JobExecutionProcessException(jl, jec, e);\n            }\n        }\n    }\n\n    public void notifyJobListenersWasVetoed(JobExecutionContext jec)\n        throws SchedulerException {\n        // build a list of all job listeners that are to be notified...\n        List<JobListener> jobListeners = buildJobListenerList();\n\n        // notify all job listeners\n        for(JobListener jl: jobListeners) {\n            try {\n                if(!matchJobListener(jl, jec.getJobDetail().getKey()))\n                    continue;\n                jl.jobExecutionVetoed(jec);\n            } catch (Exception e) {\n                throw new JobExecutionProcessException(jl, jec, e);\n            }\n        }\n    }\n\n    public void notifyJobListenersWasExecuted(JobExecutionContext jec,\n            JobExecutionException je) throws SchedulerException {\n        // build a list of all job listeners that are to be notified...\n        List<JobListener> jobListeners = buildJobListenerList();\n\n        // notify all job listeners\n        for(JobListener jl: jobListeners) {\n            try {\n                if(!matchJobListener(jl, jec.getJobDetail().getKey()))\n                    continue;\n                jl.jobWasExecuted(jec, je);\n            } catch (Exception e) {\n                throw new JobExecutionProcessException(jl, jec, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersError(String msg, SchedulerException se) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.schedulerError(msg, se);\n            } catch (Exception e) {\n                getLog()\n                        .error(\n                                \"Error while notifying SchedulerListener of error: \",\n                                e);\n                getLog().error(\"  Original error (for notification) was: {}\", msg, se);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersScheduled(Trigger trigger) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobScheduled(trigger);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of scheduled job.  Trigger={}\", trigger.getKey(), e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersUnscheduled(TriggerKey triggerKey) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                if(triggerKey == null)\n                    sl.schedulingDataCleared();\n                else\n                    sl.jobUnscheduled(triggerKey);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of unscheduled job.  Trigger={}\", triggerKey == null ? \"ALL DATA\" : triggerKey, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersFinalized(Trigger trigger) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.triggerFinalized(trigger);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of finalized trigger.  Trigger={}\", trigger.getKey(), e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersPausedTrigger(TriggerKey triggerKey) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.triggerPaused(triggerKey);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of paused trigger: {}\", triggerKey, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersPausedTriggers(String group) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.triggersPaused(group);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of paused trigger group.{}\", group, e);\n            }\n        }\n    }\n    \n    public void notifySchedulerListenersResumedTrigger(TriggerKey key) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.triggerResumed(key);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of resumed trigger: {}\", key, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersResumedTriggers(String group) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.triggersResumed(group);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of resumed group: {}\", group, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersPausedJob(JobKey key) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobPaused(key);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of paused job: {}\", key, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersPausedJobs(String group) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobsPaused(group);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of paused job group: {}\", group, e);\n            }\n        }\n    }\n    \n    public void notifySchedulerListenersResumedJob(JobKey key) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobResumed(key);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of resumed job: {}\", key, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersResumedJobs(String group) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobsResumed(group);\n            } catch (Exception e) {\n                getLog().error(\"Error while notifying SchedulerListener of resumed job group: {}\", group, e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersInStandbyMode() {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.schedulerInStandbyMode();\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of inStandByMode.\",\n                        e);\n            }\n        }\n    }\n    \n    public void notifySchedulerListenersStarted() {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.schedulerStarted();\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of startup.\",\n                        e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersStarting() {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for (SchedulerListener sl : schedListeners) {\n            try {\n                sl.schedulerStarting();\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of startup.\",\n                        e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersShutdown() {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.schedulerShutdown();\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of shutdown.\",\n                        e);\n            }\n        }\n    }\n    \n    public void notifySchedulerListenersShuttingdown() {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.schedulerShuttingdown();\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of shutdown.\",\n                        e);\n            }\n        }\n    }\n    \n    public void notifySchedulerListenersJobAdded(JobDetail jobDetail) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobAdded(jobDetail);\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of JobAdded.\",\n                        e);\n            }\n        }\n    }\n\n    public void notifySchedulerListenersJobDeleted(JobKey jobKey) {\n        // build a list of all scheduler listeners that are to be notified...\n        List<SchedulerListener> schedListeners = buildSchedulerListenerList();\n\n        // notify all scheduler listeners\n        for(SchedulerListener sl: schedListeners) {\n            try {\n                sl.jobDeleted(jobKey);\n            } catch (Exception e) {\n                getLog().error(\n                        \"Error while notifying SchedulerListener of JobAdded.\",\n                        e);\n            }\n        }\n    }\n    \n    public void setJobFactory(JobFactory factory) throws SchedulerException {\n\n        if(factory == null) {\n            throw new IllegalArgumentException(\"JobFactory cannot be set to null!\");\n        }\n\n        getLog().info(\"JobFactory set to: {}\", factory);\n\n        this.jobFactory = factory;\n    }\n    \n    public JobFactory getJobFactory()  {\n        return jobFactory;\n    }\n    \n    \n    /**\n     * Interrupt all instances of the identified InterruptableJob executing in \n     * this Scheduler instance.\n     *  \n     * <p>\n     * This method is not cluster aware.  That is, it will only interrupt \n     * instances of the identified InterruptableJob currently executing in this \n     * Scheduler instance, not across the entire cluster.\n     * </p>\n     * \n     * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey)\n     */\n    public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException {\n\n        List<JobExecutionContext> jobs = getCurrentlyExecutingJobs();\n        \n        JobDetail jobDetail;\n        Job job;\n        \n        boolean interrupted = false;\n        \n        for(JobExecutionContext jec : jobs) {\n            jobDetail = jec.getJobDetail();\n            if (jobKey.equals(jobDetail.getKey())) {\n                job = jec.getJobInstance();\n                if (job instanceof InterruptableJob) {\n                    ((InterruptableJob)job).interrupt();\n                    interrupted = true;\n                } else {\n                    throw new UnableToInterruptJobException(\n                            \"Job \" + jobDetail.getKey() +\n                            \" can not be interrupted, since it does not implement \" +                        \n                            InterruptableJob.class.getName());\n                }\n            }                        \n        }\n        \n        return interrupted;\n    }\n\n    /**\n     * Interrupt the identified InterruptableJob executing in this Scheduler instance.\n     *  \n     * <p>\n     * This method is not cluster aware.  That is, it will only interrupt \n     * instances of the identified InterruptableJob currently executing in this \n     * Scheduler instance, not across the entire cluster.\n     * </p>\n     * \n     * @see org.quartz.core.RemotableQuartzScheduler#interrupt(JobKey)\n     */\n    public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException {\n        List<JobExecutionContext> jobs = getCurrentlyExecutingJobs();\n        \n        Job job;\n        \n        for(JobExecutionContext jec : jobs) {\n            if (jec.getFireInstanceId().equals(fireInstanceId)) {\n                job = jec.getJobInstance();\n                if (job instanceof InterruptableJob) {\n                    ((InterruptableJob)job).interrupt();\n                    return true;\n                } else {\n                    throw new UnableToInterruptJobException(\n                        \"Job \" + jec.getJobDetail().getKey() +\n                        \" can not be interrupted, since it does not implement \" +                        \n                        InterruptableJob.class.getName());\n                }\n            }                        \n        }\n        \n        return false;\n    }\n    \n    private void shutdownPlugins() {\n        for (SchedulerPlugin plugin : resources.getSchedulerPlugins()) {\n            plugin.shutdown();\n        }\n    }\n\n    private void startPlugins() {\n        for (SchedulerPlugin plugin : resources.getSchedulerPlugins()) {\n            plugin.start();\n        }\n    }\n\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// ErrorLogger - Scheduler Listener Class\n//\n/////////////////////////////////////////////////////////////////////////////\n\nclass ErrorLogger extends SchedulerListenerSupport {\n    ErrorLogger() {\n    }\n    \n    @Override\n    public void schedulerError(String msg, SchedulerException cause) {\n        getLog().error(msg, cause);\n    }\n\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// ExecutingJobsManager - Job Listener Class\n//\n/////////////////////////////////////////////////////////////////////////////\n\nclass ExecutingJobsManager implements JobListener {\n    final HashMap<String, JobExecutionContext> executingJobs = new HashMap<>();\n\n    final AtomicInteger numJobsFired = new AtomicInteger(0);\n\n    ExecutingJobsManager() {\n    }\n\n    public String getName() {\n        return getClass().getName();\n    }\n\n    public int getNumJobsCurrentlyExecuting() {\n        synchronized (executingJobs) {\n            return executingJobs.size();\n        }\n    }\n\n    public void jobToBeExecuted(JobExecutionContext context) {\n        numJobsFired.incrementAndGet();\n\n        synchronized (executingJobs) {\n            executingJobs\n                    .put(((OperableTrigger)context.getTrigger()).getFireInstanceId(), context);\n        }\n    }\n\n    public void jobWasExecuted(JobExecutionContext context,\n            JobExecutionException jobException) {\n        synchronized (executingJobs) {\n            executingJobs.remove(((OperableTrigger)context.getTrigger()).getFireInstanceId());\n        }\n    }\n\n    public int getNumJobsFired() {\n        return numJobsFired.get();\n    }\n\n    public List<JobExecutionContext> getExecutingJobs() {\n        synchronized (executingJobs) {\n            return java.util.Collections.unmodifiableList(new ArrayList<>(\n                    executingJobs.values()));\n        }\n    }\n\n    public void jobExecutionVetoed(JobExecutionContext context) {\n        \n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/QuartzSchedulerMBeanImpl.java",
    "content": "package org.quartz.core;\n\nimport static org.quartz.JobKey.jobKey;\nimport static org.quartz.TriggerKey.triggerKey;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.MethodDescriptor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport javax.management.ListenerNotFoundException;\nimport javax.management.MBeanNotificationInfo;\nimport javax.management.NotCompliantMBeanException;\nimport javax.management.Notification;\nimport javax.management.NotificationBroadcasterSupport;\nimport javax.management.NotificationEmitter;\nimport javax.management.NotificationFilter;\nimport javax.management.NotificationListener;\nimport javax.management.StandardMBean;\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.TabularData;\n\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.JobListener;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerListener;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerKey;\nimport org.quartz.core.jmx.JobDetailSupport;\nimport org.quartz.core.jmx.JobExecutionContextSupport;\nimport org.quartz.core.jmx.QuartzSchedulerMBean;\nimport org.quartz.core.jmx.TriggerSupport;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.triggers.AbstractTrigger;\nimport org.quartz.spi.OperableTrigger;\n\npublic class QuartzSchedulerMBeanImpl extends StandardMBean implements\n        NotificationEmitter, QuartzSchedulerMBean, JobListener,\n        SchedulerListener {\n    private static final MBeanNotificationInfo[] NOTIFICATION_INFO;\n\n    private final QuartzScheduler scheduler;\n    private boolean sampledStatisticsEnabled;\n    private SampledStatistics sampledStatistics;\n\n    private final static SampledStatistics NULL_SAMPLED_STATISTICS = new NullSampledStatisticsImpl();\n\n    static {\n        final String[] notificationTypes = new String[] { SCHEDULER_STARTED,\n                SCHEDULER_PAUSED, SCHEDULER_SHUTDOWN, };\n        final String name = Notification.class.getName();\n        final String description = \"QuartzScheduler JMX Event\";\n        NOTIFICATION_INFO = new MBeanNotificationInfo[] { new MBeanNotificationInfo(\n                notificationTypes, name, description), };\n    }\n\n    /**\n     * emitter\n     */\n    protected final Emitter emitter = new Emitter();\n\n    /**\n     * sequenceNumber\n     */\n    protected final AtomicLong sequenceNumber = new AtomicLong();\n\n    /**\n     * QuartzSchedulerMBeanImpl\n     * \n     * @throws NotCompliantMBeanException\n     */\n    protected QuartzSchedulerMBeanImpl(QuartzScheduler scheduler)\n            throws NotCompliantMBeanException {\n        super(QuartzSchedulerMBean.class);\n        this.scheduler = scheduler;\n        this.scheduler.addInternalJobListener(this);\n        this.scheduler.addInternalSchedulerListener(this);\n        this.sampledStatistics = NULL_SAMPLED_STATISTICS;\n        this.sampledStatisticsEnabled = false;\n    }\n\n    public TabularData getCurrentlyExecutingJobs() throws Exception {\n        try {\n            List<JobExecutionContext> currentlyExecutingJobs = scheduler.getCurrentlyExecutingJobs();\n            return JobExecutionContextSupport.toTabularData(currentlyExecutingJobs);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public TabularData getAllJobDetails() throws Exception {\n        try {\n            List<JobDetail> detailList = new ArrayList<>();\n            for (String jobGroupName : scheduler.getJobGroupNames()) {\n                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroupName))) {\n                    detailList.add(scheduler.getJobDetail(jobKey));\n                }\n            }\n            return JobDetailSupport.toTabularData(detailList.toArray(new JobDetail[detailList.size()]));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<CompositeData> getAllTriggers() throws Exception {\n        try {\n            List<Trigger> triggerList = new ArrayList<>();\n            for (String triggerGroupName : scheduler.getTriggerGroupNames()) {\n                for (TriggerKey triggerKey : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName))) {\n                    triggerList.add(scheduler.getTrigger(triggerKey));\n                }\n            }\n            return TriggerSupport.toCompositeList(triggerList);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void addJob(CompositeData jobDetail, boolean replace) throws Exception {\n        try {\n            scheduler.addJob(JobDetailSupport.newJobDetail(jobDetail), replace);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    private static void invokeSetter(Object target, String attribute, Object value) throws Exception {\n        String setterName = \"set\" + Character.toUpperCase(attribute.charAt(0)) + attribute.substring(1);\n        Class<?>[] argTypes = {value.getClass()};\n        Method setter = findMethod(target.getClass(), setterName, argTypes);\n        if(setter != null) {\n            setter.invoke(target, value);\n        } else {\n            throw new Exception(\"Unable to find setter for attribute '\" + attribute\n                    + \"' and value '\" + value + \"'\");\n        }\n    }\n    \n    private static Class<?> getWrapperIfPrimitive(Class<?> c) {\n        Class<?> result = c;\n        try {\n            Field f = c.getField(\"TYPE\");\n            f.setAccessible(true);\n            result = (Class<?>) f.get(null);\n        } catch (Exception e) {\n            /**/\n        }\n        return result;\n    }\n    \n    private static Method findMethod(Class<?> targetType, String methodName,\n            Class<?>[] argTypes) throws IntrospectionException {\n        BeanInfo beanInfo = Introspector.getBeanInfo(targetType);\n        if (beanInfo != null) {\n            for(MethodDescriptor methodDesc: beanInfo.getMethodDescriptors()) {\n                Method method = methodDesc.getMethod();\n                Class<?>[] parameterTypes = method.getParameterTypes();\n                if (methodName.equals(method.getName()) && argTypes.length == parameterTypes.length) {\n                    boolean matchedArgTypes = true;\n                    for (int i = 0; i < argTypes.length; i++) { \n                        if (getWrapperIfPrimitive(argTypes[i]) != parameterTypes[i]) {\n                            matchedArgTypes = false;\n                            break;\n                        }\n                    }\n                    if (matchedArgTypes) {\n                        return method;\n                    }\n                }\n            }\n        }\n        return null;\n    }\n    \n    public void scheduleBasicJob(Map<String, Object> jobDetailInfo,\n            Map<String, Object> triggerInfo) throws Exception {\n        try {\n            JobDetail jobDetail = JobDetailSupport.newJobDetail(jobDetailInfo);\n            OperableTrigger trigger = TriggerSupport.newTrigger(triggerInfo);\n            scheduler.deleteJob(jobDetail.getKey());\n            scheduler.scheduleJob(jobDetail, trigger);\n        } catch (ParseException pe) {\n            throw pe;\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void scheduleJob(Map<String, Object> abstractJobInfo,\n            Map<String, Object> abstractTriggerInfo) throws Exception {\n        try {\n            String triggerClassName = (String) abstractTriggerInfo.remove(\"triggerClass\");\n            if(triggerClassName == null) {\n                throw new IllegalArgumentException(\"No triggerClass specified\");\n            }\n            Class<?> triggerClass = Class.forName(triggerClassName);\n            Trigger trigger = (Trigger) triggerClass.getDeclaredConstructor().newInstance();\n            \n            String jobDetailClassName = (String) abstractJobInfo.remove(\"jobDetailClass\");\n            if(jobDetailClassName == null) {\n                throw new IllegalArgumentException(\"No jobDetailClass specified\");\n            }\n            Class<?> jobDetailClass = Class.forName(jobDetailClassName);\n            JobDetail jobDetail = (JobDetail) jobDetailClass.getDeclaredConstructor().newInstance();\n            \n            String jobClassName = (String) abstractJobInfo.remove(\"jobClass\");\n            if(jobClassName == null) {\n                throw new IllegalArgumentException(\"No jobClass specified\");\n            }\n            Class<?> jobClass = Class.forName(jobClassName);\n            abstractJobInfo.put(\"jobClass\", jobClass);\n            \n            for(Map.Entry<String, Object> entry : abstractTriggerInfo.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if(\"jobDataMap\".equals(key)) {\n                    value = new JobDataMap((Map<?, ?>)value);\n                }\n                invokeSetter(trigger, key, value);\n            }\n            \n            for(Map.Entry<String, Object> entry : abstractJobInfo.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if(\"jobDataMap\".equals(key)) {\n                    value = new JobDataMap((Map<?, ?>)value);\n                }\n                invokeSetter(jobDetail, key, value);\n            }\n    \n            AbstractTrigger<?> at = (AbstractTrigger<?>)trigger;\n            at.setKey(new TriggerKey(at.getName(), at.getGroup()));\n            \n            Date startDate = at.getStartTime();\n            if(startDate == null || startDate.before(new Date())) {\n                at.setStartTime(new Date());\n            }\n            \n            scheduler.deleteJob(jobDetail.getKey());\n            scheduler.scheduleJob(jobDetail, trigger);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    public void scheduleJob(String jobName, String jobGroup,\n            Map<String, Object> abstractTriggerInfo) throws Exception {\n        try {\n            JobKey jobKey = new JobKey(jobName, jobGroup);\n            JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n            if(jobDetail == null) {\n                throw new IllegalArgumentException(\"No such job '\" + jobKey + \"'\");\n            }\n            \n            String triggerClassName = (String) abstractTriggerInfo.remove(\"triggerClass\");\n            if(triggerClassName == null) {\n                throw new IllegalArgumentException(\"No triggerClass specified\");\n            }\n            Class<?> triggerClass = Class.forName(triggerClassName);\n            Trigger trigger = (Trigger) triggerClass.getDeclaredConstructor().newInstance();\n            \n            for(Map.Entry<String, Object> entry : abstractTriggerInfo.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if(\"jobDataMap\".equals(key)) {\n                    value = new JobDataMap((Map<?, ?>)value);\n                }\n                invokeSetter(trigger, key, value);\n            }\n            \n            AbstractTrigger<?> at = (AbstractTrigger<?>)trigger;\n            at.setKey(new TriggerKey(at.getName(), at.getGroup()));\n            \n            Date startDate = at.getStartTime();\n            if(startDate == null || startDate.before(new Date())) {\n                at.setStartTime(new Date());\n            }\n            \n            scheduler.scheduleJob(trigger);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    public void addJob(Map<String, Object> abstractJobInfo,    boolean replace) throws Exception {\n        try {\n            String jobDetailClassName = (String) abstractJobInfo.remove(\"jobDetailClass\");\n            if(jobDetailClassName == null) {\n                throw new IllegalArgumentException(\"No jobDetailClass specified\");\n            }\n            Class<?> jobDetailClass = Class.forName(jobDetailClassName);\n            JobDetail jobDetail = (JobDetail) jobDetailClass.getDeclaredConstructor().newInstance();\n            \n            String jobClassName = (String) abstractJobInfo.remove(\"jobClass\");\n            if(jobClassName == null) {\n                throw new IllegalArgumentException(\"No jobClass specified\");\n            }\n            Class<?> jobClass = Class.forName(jobClassName);\n            abstractJobInfo.put(\"jobClass\", jobClass);\n            \n            for(Map.Entry<String, Object> entry : abstractJobInfo.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if(\"jobDataMap\".equals(key)) {\n                    value = new JobDataMap((Map<?, ?>)value);\n                }\n                invokeSetter(jobDetail, key, value);\n            }\n    \n            scheduler.addJob(jobDetail, replace);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    private Exception newPlainException(Exception e) {\n        String type = e.getClass().getName();\n        if(type.startsWith(\"java.\") || type.startsWith(\"javax.\")) {\n            return e;\n        } else {\n            Exception result = new Exception(e.getMessage());\n            result.setStackTrace(e.getStackTrace());\n            return result;\n        }\n    }\n    \n    public void deleteCalendar(String calendarName) throws Exception {\n        try {\n            scheduler.deleteCalendar(calendarName);\n        } catch(Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public boolean deleteJob(String jobName, String jobGroupName) throws Exception {\n        try {\n            return scheduler.deleteJob(jobKey(jobName, jobGroupName));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<String> getCalendarNames()    throws Exception {\n        try {\n            return scheduler.getCalendarNames();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public CompositeData getJobDetail(String jobName, String jobGroupName)\n      throws Exception {\n        try {\n            JobDetail jobDetail = scheduler.getJobDetail(jobKey(jobName, jobGroupName));\n            return JobDetailSupport.toCompositeData(jobDetail);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<String> getJobGroupNames()    throws Exception {\n        try {\n            return scheduler.getJobGroupNames();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<String> getJobNames(String groupName) throws Exception {\n        try {\n            List<String> jobNames = new ArrayList<>();\n            for(JobKey key: scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {\n                jobNames.add(key.getName());\n            }\n            return jobNames;\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public String getJobStoreClassName() {\n        return scheduler.getJobStoreClass().getName();\n    }\n\n    public Set<String> getPausedTriggerGroups() throws Exception {\n        try {\n            return scheduler.getPausedTriggerGroups();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public CompositeData getTrigger(String name, String groupName) throws Exception {\n        try {\n            Trigger trigger = scheduler.getTrigger(triggerKey(name, groupName));\n            return TriggerSupport.toCompositeData(trigger);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<String> getTriggerGroupNames()    throws Exception {\n        try {\n            return scheduler.getTriggerGroupNames();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<String> getTriggerNames(String groupName) throws Exception {\n        try {\n            List<String> triggerNames = new ArrayList<>();\n            for(TriggerKey key: scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName))) {\n                triggerNames.add(key.getName());\n            }\n            return triggerNames;\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public String getTriggerState(String triggerName, String triggerGroupName) throws Exception {\n        try {\n            TriggerKey triggerKey = triggerKey(triggerName, triggerGroupName);\n            TriggerState ts = scheduler.getTriggerState(triggerKey);\n            return ts.name();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public List<CompositeData> getTriggersOfJob(String jobName, String jobGroupName) throws Exception {\n        try {\n            JobKey jobKey = jobKey(jobName, jobGroupName);\n            return TriggerSupport.toCompositeList(scheduler.getTriggersOfJob(jobKey));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public boolean interruptJob(String jobName, String jobGroupName) throws Exception {\n        try {\n            return scheduler.interrupt(jobKey(jobName, jobGroupName));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public boolean interruptJob(String fireInstanceId) throws Exception {\n        try {\n            return scheduler.interrupt(fireInstanceId);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public Date scheduleJob(String jobName, String jobGroup,\n            String triggerName, String triggerGroup) throws Exception {\n        try {\n            JobKey jobKey = jobKey(jobName, jobGroup);\n            JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n            if (jobDetail == null) {\n                throw new IllegalArgumentException(\"No such job: \" + jobKey);\n            }\n            TriggerKey triggerKey = triggerKey(triggerName, triggerGroup);\n            Trigger trigger = scheduler.getTrigger(triggerKey);\n            if (trigger == null) {\n                throw new IllegalArgumentException(\"No such trigger: \" + triggerKey);\n            }\n            return scheduler.scheduleJob(jobDetail, trigger);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public boolean unscheduleJob(String triggerName, String triggerGroup) throws Exception {\n        try {\n            return scheduler.unscheduleJob(triggerKey(triggerName, triggerGroup));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n   public void clear() throws Exception {\n       try {\n           scheduler.clear();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public String getVersion() {\n        return scheduler.getVersion();\n    }\n\n    public boolean isShutdown() {\n        return scheduler.isShutdown();\n    }\n\n    public boolean isStarted() {\n        return scheduler.isStarted();\n    }\n\n    public void start() throws Exception {\n        try {\n            scheduler.start();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void shutdown() {\n        scheduler.shutdown();\n    }\n\n    public void standby() {\n        scheduler.standby();\n    }\n\n    public boolean isStandbyMode() {\n        return scheduler.isInStandbyMode();\n    }\n\n    public String getSchedulerName() {\n        return scheduler.getSchedulerName();\n    }\n\n    public String getSchedulerInstanceId() {\n        return scheduler.getSchedulerInstanceId();\n    }\n\n    public String getThreadPoolClassName() {\n        return scheduler.getThreadPoolClass().getName();\n    }\n\n    public int getThreadPoolSize() {\n        return scheduler.getThreadPoolSize();\n    }\n\n    public void pauseJob(String jobName, String jobGroup) throws Exception {\n        try {\n            scheduler.pauseJob(jobKey(jobName, jobGroup));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void pauseJobs(GroupMatcher<JobKey> matcher) throws Exception {\n        try {\n            scheduler.pauseJobs(matcher);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    public void pauseJobGroup(String jobGroup) throws Exception {\n        pauseJobs(GroupMatcher.groupEquals(jobGroup));\n    }\n\n    public void pauseJobsStartingWith(String jobGroupPrefix) throws Exception {\n        pauseJobs(GroupMatcher.groupStartsWith(jobGroupPrefix));\n    }\n\n    public void pauseJobsEndingWith(String jobGroupSuffix) throws Exception {\n        pauseJobs(GroupMatcher.groupEndsWith(jobGroupSuffix));\n    }\n\n    public void pauseJobsContaining(String jobGroupToken) throws Exception {\n        pauseJobs(GroupMatcher.groupContains(jobGroupToken));\n    }\n\n    public void pauseJobsAll() throws Exception {\n        pauseJobs(GroupMatcher.anyJobGroup());\n    }\n\n    public void pauseAllTriggers() throws Exception {\n        try {\n            scheduler.pauseAll();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    private void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws Exception {\n        try {\n            scheduler.pauseTriggers(matcher);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    public void pauseTriggerGroup(String triggerGroup) throws Exception {\n        pauseTriggers(GroupMatcher.groupEquals(triggerGroup));\n    }\n\n    public void pauseTriggersStartingWith(String triggerGroupPrefix) throws Exception {\n        pauseTriggers(GroupMatcher.groupStartsWith(triggerGroupPrefix));\n    }\n\n    public void pauseTriggersEndingWith(String triggerGroupSuffix) throws Exception {\n        pauseTriggers(GroupMatcher.groupEndsWith(triggerGroupSuffix));\n    }\n\n    public void pauseTriggersContaining(String triggerGroupToken) throws Exception {\n        pauseTriggers(GroupMatcher.groupContains(triggerGroupToken));\n    }\n\n    public void pauseTriggersAll() throws Exception {\n        pauseTriggers(GroupMatcher.anyTriggerGroup());\n    }\n\n    public void pauseTrigger(String triggerName, String triggerGroup) throws Exception {\n        try {\n            scheduler.pauseTrigger(triggerKey(triggerName, triggerGroup));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void resumeAllTriggers() throws Exception {\n        try {\n            scheduler.resumeAll();\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void resumeJob(String jobName, String jobGroup) throws Exception {\n        try {\n            scheduler.resumeJob(jobKey(jobName, jobGroup));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void resumeJobs(GroupMatcher<JobKey> matcher) throws Exception {\n        try {\n            scheduler.resumeJobs(matcher);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void resumeJobGroup(String jobGroup) throws Exception {\n        resumeJobs(GroupMatcher.groupEquals(jobGroup));\n    }\n\n    public void resumeJobsStartingWith(String jobGroupPrefix) throws Exception {\n        resumeJobs(GroupMatcher.groupStartsWith(jobGroupPrefix));\n    }\n\n    public void resumeJobsEndingWith(String jobGroupSuffix) throws Exception {\n        resumeJobs(GroupMatcher.groupEndsWith(jobGroupSuffix));\n    }\n\n    public void resumeJobsContaining(String jobGroupToken) throws Exception {\n        resumeJobs(GroupMatcher.groupContains(jobGroupToken));\n    }\n\n    public void resumeJobsAll() throws Exception {\n        resumeJobs(GroupMatcher.anyJobGroup());\n    }\n\n    public void resumeTrigger(String triggerName, String triggerGroup) throws Exception {\n        try {\n            scheduler.resumeTrigger(triggerKey(triggerName, triggerGroup));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    private void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws Exception {\n        try {\n            scheduler.resumeTriggers(matcher);\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    public void resumeTriggerGroup(String triggerGroup) throws Exception {\n        resumeTriggers(GroupMatcher.groupEquals(triggerGroup));\n    }\n\n    public void resumeTriggersStartingWith(String triggerGroupPrefix) throws Exception {\n        resumeTriggers(GroupMatcher.groupStartsWith(triggerGroupPrefix));\n    }\n\n    public void resumeTriggersEndingWith(String triggerGroupSuffix) throws Exception {\n        resumeTriggers(GroupMatcher.groupEndsWith(triggerGroupSuffix));\n    }\n\n    public void resumeTriggersContaining(String triggerGroupToken) throws Exception {\n        resumeTriggers(GroupMatcher.groupContains(triggerGroupToken));\n    }\n\n    public void resumeTriggersAll() throws Exception {\n        resumeTriggers(GroupMatcher.anyTriggerGroup());\n    }\n\n    public void triggerJob(String jobName, String jobGroup, Map<String, String> jobDataMap)\n            throws Exception {\n        try {\n            scheduler.triggerJob(jobKey(jobName, jobGroup), new JobDataMap(jobDataMap));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n\n    public void triggerJob(CompositeData trigger) throws Exception {\n        try {\n            scheduler.triggerJob(TriggerSupport.newTrigger(trigger));\n        } catch (Exception e) {\n            throw newPlainException(e);\n        }\n    }\n    \n    // ScheduleListener\n\n    public void jobAdded(JobDetail jobDetail) {\n        sendNotification(JOB_ADDED, JobDetailSupport.toCompositeData(jobDetail));\n    }\n\n    public void jobDeleted(JobKey jobKey) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"jobName\", jobKey.getName());\n        map.put(\"jobGroup\", jobKey.getGroup());\n        sendNotification(JOB_DELETED, map);\n    }\n\n    public void jobScheduled(Trigger trigger) {\n        sendNotification(JOB_SCHEDULED, TriggerSupport.toCompositeData(trigger));\n    }\n\n    public void jobUnscheduled(TriggerKey triggerKey) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"triggerName\", triggerKey.getName());\n        map.put(\"triggerGroup\", triggerKey.getGroup());\n        sendNotification(JOB_UNSCHEDULED, map);\n    }\n    \n    public void schedulingDataCleared() {\n        sendNotification(SCHEDULING_DATA_CLEARED);\n    }\n    \n    public void jobPaused(JobKey jobKey) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"jobName\", jobKey.getName());\n        map.put(\"jobGroup\", jobKey.getGroup());\n        sendNotification(JOBS_PAUSED, map);\n    }\n\n    public void jobsPaused(String jobGroup) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"jobName\", null);\n        map.put(\"jobGroup\", jobGroup);\n        sendNotification(JOBS_PAUSED, map);\n    }\n    \n    public void jobsResumed(String jobGroup) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"jobName\", null);\n        map.put(\"jobGroup\", jobGroup);\n        sendNotification(JOBS_RESUMED, map);\n    }\n\n    public void jobResumed(JobKey jobKey) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"jobName\", jobKey.getName());\n        map.put(\"jobGroup\", jobKey.getGroup());\n        sendNotification(JOBS_RESUMED, map);\n    }\n    \n    public void schedulerError(String msg, SchedulerException cause) {\n        sendNotification(SCHEDULER_ERROR, cause.getMessage());\n    }\n\n    public void schedulerStarted() {\n        sendNotification(SCHEDULER_STARTED);\n    }\n    \n    //not doing anything, just like schedulerShuttingdown\n    public void schedulerStarting() {\n    }\n\n    public void schedulerInStandbyMode() {\n        sendNotification(SCHEDULER_PAUSED);\n    }\n\n    public void schedulerShutdown() {\n        scheduler.removeInternalSchedulerListener(this);\n        scheduler.removeInternalJobListener(getName());\n\n        sendNotification(SCHEDULER_SHUTDOWN);\n    }\n\n    public void schedulerShuttingdown() {\n    }\n\n    public void triggerFinalized(Trigger trigger) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"triggerName\", trigger.getKey().getName());\n        map.put(\"triggerGroup\", trigger.getKey().getGroup());\n        sendNotification(TRIGGER_FINALIZED, map);\n    }\n\n    public void triggersPaused(String triggerGroup) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"triggerName\", null);\n        map.put(\"triggerGroup\", triggerGroup);\n        sendNotification(TRIGGERS_PAUSED, map);\n    }\n\n    public void triggerPaused(TriggerKey triggerKey) {\n        Map<String, String> map = new HashMap<>();\n        if(triggerKey != null) {\n            map.put(\"triggerName\", triggerKey.getName());\n            map.put(\"triggerGroup\", triggerKey.getGroup());\n        }\n        sendNotification(TRIGGERS_PAUSED, map);\n    }\n\n    public void triggersResumed(String triggerGroup) {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"triggerName\", null);\n        map.put(\"triggerGroup\", triggerGroup);\n        sendNotification(TRIGGERS_RESUMED, map);\n    }\n\n    public void triggerResumed(TriggerKey triggerKey) {\n        Map<String, String> map = new HashMap<>();\n        if(triggerKey != null) {\n            map.put(\"triggerName\", triggerKey.getName());\n            map.put(\"triggerGroup\", triggerKey.getGroup());\n        }\n        sendNotification(TRIGGERS_RESUMED, map);\n    }\n    \n    // JobListener\n\n    public String getName() {\n        return \"QuartzSchedulerMBeanImpl.listener\";\n    }\n\n    public void jobExecutionVetoed(JobExecutionContext context) {\n        try {\n            sendNotification(JOB_EXECUTION_VETOED, JobExecutionContextSupport\n                    .toCompositeData(context));\n        } catch (Exception e) {\n            throw new RuntimeException(newPlainException(e));\n        }\n    }\n\n    public void jobToBeExecuted(JobExecutionContext context) {\n        try {\n            sendNotification(JOB_TO_BE_EXECUTED, JobExecutionContextSupport\n                    .toCompositeData(context));\n        } catch (Exception e) {\n            throw new RuntimeException(newPlainException(e));\n        }\n    }\n\n    public void jobWasExecuted(JobExecutionContext context,\n            JobExecutionException jobException) {\n        try {\n            sendNotification(JOB_WAS_EXECUTED, JobExecutionContextSupport\n                    .toCompositeData(context));\n        } catch (Exception e) {\n            throw new RuntimeException(newPlainException(e));\n        }\n    }\n\n    // NotificationBroadcaster\n\n    /**\n     * sendNotification\n     * \n     * @param eventType\n     */\n    public void sendNotification(String eventType) {\n        sendNotification(eventType, null, null);\n    }\n\n    /**\n     * sendNotification\n     * \n     * @param eventType\n     * @param data\n     */\n    public void sendNotification(String eventType, Object data) {\n        sendNotification(eventType, data, null);\n    }\n\n    /**\n     * sendNotification\n     * \n     * @param eventType\n     * @param data\n     * @param msg\n     */\n    public void sendNotification(String eventType, Object data, String msg) {\n        Notification notification = new Notification(eventType, this, sequenceNumber\n                .incrementAndGet(), System.currentTimeMillis(), msg);\n        if (data != null) {\n            notification.setUserData(data);\n        }\n        emitter.sendNotification(notification);\n    }\n\n    /**\n     * @author gkeim\n     */\n    private class Emitter extends NotificationBroadcasterSupport {\n        /**\n         * @see javax.management.NotificationBroadcasterSupport#getNotificationInfo()\n         */\n        @Override\n        public MBeanNotificationInfo[] getNotificationInfo() {\n            return QuartzSchedulerMBeanImpl.this.getNotificationInfo();\n        }\n    }\n\n    /**\n     * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener,\n     *      javax.management.NotificationFilter, java.lang.Object)\n     */\n    public void addNotificationListener(NotificationListener listener,\n            NotificationFilter filter, Object callBack) {\n        emitter.addNotificationListener(listener, filter, callBack);\n    }\n\n    /**\n     * @see javax.management.NotificationBroadcaster#getNotificationInfo()\n     */\n    public MBeanNotificationInfo[] getNotificationInfo() {\n        return NOTIFICATION_INFO;\n    }\n\n    /**\n     * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)\n     */\n    public void removeNotificationListener(NotificationListener listener)\n            throws ListenerNotFoundException {\n        emitter.removeNotificationListener(listener);\n    }\n\n    /**\n     * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener,\n     *      javax.management.NotificationFilter, java.lang.Object)\n     */\n    public void removeNotificationListener(NotificationListener listener,\n            NotificationFilter filter, Object callBack)\n            throws ListenerNotFoundException {\n        emitter.removeNotificationListener(listener, filter, callBack);\n    }\n\n    public synchronized boolean isSampledStatisticsEnabled() {\n        return sampledStatisticsEnabled;\n    }\n\n    public void setSampledStatisticsEnabled(boolean enabled) {\n        if (enabled != this.sampledStatisticsEnabled) {\n            this.sampledStatisticsEnabled = enabled;\n            if(enabled) {\n                this.sampledStatistics = new SampledStatisticsImpl(scheduler);\n            }\n            else {\n                 this.sampledStatistics.shutdown(); \n                 this.sampledStatistics = NULL_SAMPLED_STATISTICS;\n            }\n            sendNotification(SAMPLED_STATISTICS_ENABLED, enabled);\n        }\n    }\n\n    public long getJobsCompletedMostRecentSample() {\n        return this.sampledStatistics.getJobsCompletedMostRecentSample();\n    }\n\n    public long getJobsExecutedMostRecentSample() {\n        return this.sampledStatistics.getJobsExecutingMostRecentSample();\n    }\n\n    public long getJobsScheduledMostRecentSample() {\n        return this.sampledStatistics.getJobsScheduledMostRecentSample();\n    }\n\n    public Map<String, Long> getPerformanceMetrics() {\n        Map<String, Long> result = new HashMap<>();\n        result.put(\"JobsCompleted\", getJobsCompletedMostRecentSample());\n        result.put(\"JobsExecuted\", getJobsExecutedMostRecentSample());\n        result.put(\"JobsScheduled\", getJobsScheduledMostRecentSample());\n        return result;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/QuartzSchedulerResources.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.core;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.quartz.management.ManagementRESTServiceConfiguration;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.quartz.spi.ThreadExecutor;\nimport org.quartz.spi.ThreadPool;\n\n/**\n * <p>\n * Contains all of the resources (<code>JobStore</code>,<code>ThreadPool</code>,\n * etc.) necessary to create a <code>{@link QuartzScheduler}</code> instance.\n * </p>\n * \n * @see QuartzScheduler\n * \n * @author James House\n */\npublic class QuartzSchedulerResources {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String CREATE_REGISTRY_NEVER = \"never\";\n\n    public static final String CREATE_REGISTRY_ALWAYS = \"always\";\n\n    public static final String CREATE_REGISTRY_AS_NEEDED = \"as_needed\";\n\n    private String name;\n\n    private String instanceId;\n\n    private String threadName;\n    \n    private String rmiRegistryHost = null;\n\n    private int rmiRegistryPort = 1099;\n\n    private int rmiServerPort = -1;\n\n    private String rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER;\n\n    private ThreadPool threadPool;\n\n    private JobStore jobStore;\n\n    private JobRunShellFactory jobRunShellFactory;\n\n    private final List<SchedulerPlugin> schedulerPlugins = new ArrayList<>(10);\n    \n    private boolean makeSchedulerThreadDaemon = false;\n\n    private boolean threadsInheritInitializersClassLoadContext = false;\n\n    private String rmiBindName;\n    \n    private boolean jmxExport;\n    \n    private String jmxObjectName;\n\n    private ManagementRESTServiceConfiguration managementRESTServiceConfiguration;\n\n    private ThreadExecutor threadExecutor;\n\n    private long batchTimeWindow = 0;\n\n    private int maxBatchSize = 1;\n\n    private boolean interruptJobsOnShutdown = false;\n    private boolean interruptJobsOnShutdownWithWait = false;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create an instance with no properties initialized.\n     * </p>\n     */\n    public QuartzSchedulerResources() {\n        // do nothing...\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name for the <code>{@link QuartzScheduler}</code>.\n     * </p>\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * <p>\n     * Set the name for the <code>{@link QuartzScheduler}</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty.\n     */\n    public void setName(String name) {\n        if (name == null || name.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Scheduler name cannot be empty.\");\n        }\n\n        this.name = name;\n        \n        if (threadName == null) {\n            // thread name not already set, use default thread name\n            setThreadName(name + \"_QuartzSchedulerThread\");\n        }        \n    }\n\n    /**\n     * <p>\n     * Get the instance Id for the <code>{@link QuartzScheduler}</code>.\n     * </p>\n     */\n    public String getInstanceId() {\n        return instanceId;\n    }\n\n    /**\n     * <p>\n     * Set the name for the <code>{@link QuartzScheduler}</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty.\n     */\n    public void setInstanceId(String instanceId) {\n        if (instanceId == null || instanceId.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Scheduler instanceId cannot be empty.\");\n        }\n\n        this.instanceId = instanceId;\n    }\n\n    public static String getUniqueIdentifier(String schedName,\n            String schedInstId) {\n        return schedName + \"_$_\" + schedInstId;\n    }\n\n    public String getUniqueIdentifier() {\n        return getUniqueIdentifier(name, instanceId);\n    }\n\n    /**\n     * <p>\n     * Get the host name of the RMI Registry that the scheduler should export\n     * itself to.\n     * </p>\n     */\n    public String getRMIRegistryHost() {\n        return rmiRegistryHost;\n    }\n\n    /**\n     * <p>\n     * Set the host name of the RMI Registry that the scheduler should export\n     * itself to.\n     * </p>\n     */\n    public void setRMIRegistryHost(String hostName) {\n        this.rmiRegistryHost = hostName;\n    }\n\n    /**\n     * <p>\n     * Get the port number of the RMI Registry that the scheduler should export\n     * itself to.\n     * </p>\n     */\n    public int getRMIRegistryPort() {\n        return rmiRegistryPort;\n    }\n\n    /**\n     * <p>\n     * Set the port number of the RMI Registry that the scheduler should export\n     * itself to.\n     * </p>\n     */\n    public void setRMIRegistryPort(int port) {\n        this.rmiRegistryPort = port;\n    }\n\n\n    /**\n     * <p>\n     * Get the port number the scheduler server will be bound to.\n     * </p>\n     */\n    public int getRMIServerPort() {\n        return rmiServerPort;\n    }\n\n    /**\n     * <p>\n     * Set the port number the scheduler server will be bound to.\n     * </p>\n     */\n    public void setRMIServerPort(int port) {\n        this.rmiServerPort = port;\n    }\n    \n    /**\n     * <p>\n     * Get the setting of whether or not Quartz should create an RMI Registry,\n     * and if so, how.\n     * </p>\n     */\n    public String getRMICreateRegistryStrategy() {\n        return rmiCreateRegistryStrategy;\n    }\n\n    /**\n     * <p>\n     * Get the name for the <code>{@link QuartzSchedulerThread}</code>.\n     * </p>\n     */\n    public String getThreadName() {\n        return threadName;\n    }\n\n    /**\n     * <p>\n     * Set the name for the <code>{@link QuartzSchedulerThread}</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty.\n     */\n    public void setThreadName(String threadName) {\n        if (threadName == null || threadName.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Scheduler thread name cannot be empty.\");\n        }\n\n        this.threadName = threadName;\n    }    \n    \n    /**\n     * <p>\n     * Set whether or not Quartz should create an RMI Registry, and if so, how.\n     * </p>\n     * \n     * @see #CREATE_REGISTRY_ALWAYS\n     * @see #CREATE_REGISTRY_AS_NEEDED\n     * @see #CREATE_REGISTRY_NEVER\n     */\n    public void setRMICreateRegistryStrategy(String rmiCreateRegistryStrategy) {\n        if (rmiCreateRegistryStrategy == null\n                || rmiCreateRegistryStrategy.trim().isEmpty()) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER;\n        } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(\"true\")) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED;\n        } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(\"false\")) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER;\n        } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_ALWAYS)) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_ALWAYS;\n        } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_AS_NEEDED)) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_AS_NEEDED;\n        } else if (rmiCreateRegistryStrategy.equalsIgnoreCase(CREATE_REGISTRY_NEVER)) {\n            rmiCreateRegistryStrategy = CREATE_REGISTRY_NEVER;\n        } else {\n            throw new IllegalArgumentException(\n                    \"Failed to set RMICreateRegistryStrategy - strategy unknown: '\"\n                            + rmiCreateRegistryStrategy + \"'\");\n        }\n\n        this.rmiCreateRegistryStrategy = rmiCreateRegistryStrategy;\n    }\n\n    /**\n     * <p>\n     * Get the <code>{@link ThreadPool}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     */\n    public ThreadPool getThreadPool() {\n        return threadPool;\n    }\n\n    /**\n     * <p>\n     * Set the <code>{@link ThreadPool}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if threadPool is null.\n     */\n    public void setThreadPool(ThreadPool threadPool) {\n        if (threadPool == null) {\n            throw new IllegalArgumentException(\"ThreadPool cannot be null.\");\n        }\n\n        this.threadPool = threadPool;\n    }\n\n    /**\n     * <p>\n     * Get the <code>{@link JobStore}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     */\n    public JobStore getJobStore() {\n        return jobStore;\n    }\n\n    /**\n     * <p>\n     * Set the <code>{@link JobStore}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if jobStore is null.\n     */\n    public void setJobStore(JobStore jobStore) {\n        if (jobStore == null) {\n            throw new IllegalArgumentException(\"JobStore cannot be null.\");\n        }\n\n        this.jobStore = jobStore;\n    }\n\n    /**\n     * <p>\n     * Get the <code>{@link JobRunShellFactory}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     */\n    public JobRunShellFactory getJobRunShellFactory() {\n        return jobRunShellFactory;\n    }\n\n    /**\n     * <p>\n     * Set the <code>{@link JobRunShellFactory}</code> for the <code>{@link QuartzScheduler}</code>\n     * to use.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if jobRunShellFactory is null.\n     */\n    public void setJobRunShellFactory(JobRunShellFactory jobRunShellFactory) {\n        if (jobRunShellFactory == null) {\n            throw new IllegalArgumentException(\n                    \"JobRunShellFactory cannot be null.\");\n        }\n\n        this.jobRunShellFactory = jobRunShellFactory;\n    }\n\n    /**\n     * <p>\n     * Add the given <code>{@link org.quartz.spi.SchedulerPlugin}</code> for the \n     * <code>{@link QuartzScheduler}</code> to use. This method expects the plugin's\n     * \"initialize\" method to be invoked externally (either before or after\n     * this method is called).\n     * </p>\n     */\n    public void addSchedulerPlugin(SchedulerPlugin plugin) {\n        schedulerPlugins.add(plugin);\n    }\n    \n    /**\n     * <p>\n     * Get the <code>List</code> of all \n     * <code>{@link org.quartz.spi.SchedulerPlugin}</code>s for the \n     * <code>{@link QuartzScheduler}</code> to use.\n     * </p>\n     */\n    public List<SchedulerPlugin> getSchedulerPlugins() {\n        return schedulerPlugins;\n    }\n\n    /**\n     * Get whether to mark the Quartz scheduling thread as daemon.\n     * \n     * @see Thread#setDaemon(boolean)\n     */\n    public boolean getMakeSchedulerThreadDaemon() {\n        return makeSchedulerThreadDaemon;\n    }\n\n    /**\n     * Set whether to mark the Quartz scheduling thread as daemon.\n     * \n     * @see Thread#setDaemon(boolean)\n     */\n    public void setMakeSchedulerThreadDaemon(boolean makeSchedulerThreadDaemon) {\n        this.makeSchedulerThreadDaemon = makeSchedulerThreadDaemon;\n    }\n\n    /**\n     * Get whether to set the class load context of spawned threads to that\n     * of the initializing thread.\n     */\n    public boolean isThreadsInheritInitializersClassLoadContext() {\n        return threadsInheritInitializersClassLoadContext;\n    }\n\n    /**\n     * Set whether to set the class load context of spawned threads to that\n     * of the initializing thread.\n     */\n    public void setThreadsInheritInitializersClassLoadContext(\n            boolean threadsInheritInitializersClassLoadContext) {\n        this.threadsInheritInitializersClassLoadContext = threadsInheritInitializersClassLoadContext;\n    }\n\n    /**\n     * Get the name under which to bind the QuartzScheduler in RMI.  Will \n     * return the value of the uniqueIdentifier property if explicit RMI bind \n     * name was never set.\n     * \n     * @see #getUniqueIdentifier()\n     */\n    public String getRMIBindName() {\n        return (rmiBindName == null) ? getUniqueIdentifier() : rmiBindName;\n    }\n\n    /**\n     * Set the name under which to bind the QuartzScheduler in RMI.  If unset, \n     * defaults to the value of the uniqueIdentifier property.\n     * \n     * @see #getUniqueIdentifier()\n     */\n    public void setRMIBindName(String rmiBindName) {\n        this.rmiBindName = rmiBindName;\n    }\n\n    /**\n     * Get whether the QuartzScheduler should be registered with the local \n     * MBeanServer.\n     */\n    public boolean getJMXExport() {\n        return jmxExport;\n    }\n\n    /**\n     * Set whether the QuartzScheduler should be registered with the local \n     * MBeanServer.\n     */\n    public void setJMXExport(boolean jmxExport) {\n        this.jmxExport = jmxExport;\n    }\n\n    /**\n     * Get the name under which the QuartzScheduler should be registered with \n     * the local MBeanServer.  If unset, defaults to the value calculated by \n     * <code>generateJMXObjectName</code>.\n     * \n     * @see #generateJMXObjectName(String, String)\n     */\n    public String getJMXObjectName() {\n        return (jmxObjectName == null) ? generateJMXObjectName(name, instanceId) : jmxObjectName;\n    }\n\n    /**\n     * Set the name under which the QuartzScheduler should be registered with \n     * the local MBeanServer.  If unset, defaults to the value calculated by \n     * <code>generateJMXObjectName</code>.\n     * \n     * @see #generateJMXObjectName(String, String)\n     */\n    public void setJMXObjectName(String jmxObjectName) {\n        this.jmxObjectName = jmxObjectName;\n    }\n\n    /**\n     * Get the ThreadExecutor which runs the QuartzSchedulerThread\n     */\n    public ThreadExecutor getThreadExecutor() {\n        return threadExecutor;\n    }\n\n    /**\n     * Set the ThreadExecutor which runs the QuartzSchedulerThread\n     */\n    public void setThreadExecutor(ThreadExecutor threadExecutor) {\n        this.threadExecutor = threadExecutor;\n    }\n\n    /**\n     * Create the name under which this scheduler should be registered in JMX.\n     * <p>\n     * The name is composed as:\n     * quartz:type=QuartzScheduler,name=<i>[schedName]</i>,instance=<i>[schedInstId]</i>\n     * </p>\n     */\n    public static String generateJMXObjectName(String schedName, String schedInstId) {\n        return \"quartz:type=QuartzScheduler\" + \",name=\"\n            + schedName.replaceAll(\":|=|\\n\", \".\")\n            + \",instance=\" + schedInstId;\n    }\n\n    public long getBatchTimeWindow() {\n        return batchTimeWindow;\n    }\n\n    public void setBatchTimeWindow(long batchTimeWindow) {\n        this.batchTimeWindow = batchTimeWindow;\n    }\n\n    public int getMaxBatchSize() {\n      return maxBatchSize;\n    }\n\n    public void setMaxBatchSize(int maxBatchSize) {\n      this.maxBatchSize = maxBatchSize;\n    }\n    \n    public boolean isInterruptJobsOnShutdown() {\n        return interruptJobsOnShutdown;\n    }\n\n    public void setInterruptJobsOnShutdown(boolean interruptJobsOnShutdown) {\n        this.interruptJobsOnShutdown = interruptJobsOnShutdown;\n    }\n    \n    public boolean isInterruptJobsOnShutdownWithWait() {\n        return interruptJobsOnShutdownWithWait;\n    }\n\n    public void setInterruptJobsOnShutdownWithWait(\n            boolean interruptJobsOnShutdownWithWait) {\n        this.interruptJobsOnShutdownWithWait = interruptJobsOnShutdownWithWait;\n    }\n\n\n    public ManagementRESTServiceConfiguration getManagementRESTServiceConfiguration() {\n        return managementRESTServiceConfiguration;\n    }\n\n    public void setManagementRESTServiceConfiguration(ManagementRESTServiceConfiguration managementRESTServiceConfiguration) {\n        this.managementRESTServiceConfiguration = managementRESTServiceConfiguration;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/QuartzSchedulerThread.java",
    "content": "\n/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.core;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.quartz.JobPersistenceException;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.quartz.spi.TriggerFiredResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * The thread responsible for performing the work of firing <code>{@link Trigger}</code>\n * s that are registered with the <code>{@link QuartzScheduler}</code>.\n * </p>\n *\n * @see QuartzScheduler\n * @see org.quartz.Job\n * @see Trigger\n *\n * @author James House\n */\npublic class QuartzSchedulerThread extends Thread {\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    private QuartzScheduler qs;\n\n    private QuartzSchedulerResources qsRsrcs;\n\n    private final Object sigLock = new Object();\n\n    private boolean signaled;\n    private long signaledNextFireTime;\n\n    private boolean paused;\n\n    private final AtomicBoolean halted;\n\n    private final Random random = new Random(System.currentTimeMillis());\n\n    // When the scheduler finds there is no current trigger to fire, how long\n    // it should wait until checking again...\n    private static final long DEFAULT_IDLE_WAIT_TIME = 30L * 1000L;\n\n    private long idleWaitTime = DEFAULT_IDLE_WAIT_TIME;\n\n    private int idleWaitVariableness = 7 * 1000;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Construct a new <code>QuartzSchedulerThread</code> for the given\n     * <code>QuartzScheduler</code> as a non-daemon <code>Thread</code>\n     * with normal priority.\n     * </p>\n     */\n    QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs) {\n        this(qs, qsRsrcs, qsRsrcs.getMakeSchedulerThreadDaemon(), Thread.NORM_PRIORITY);\n    }\n\n    /**\n     * <p>\n     * Construct a new <code>QuartzSchedulerThread</code> for the given\n     * <code>QuartzScheduler</code> as a <code>Thread</code> with the given\n     * attributes.\n     * </p>\n     */\n    QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, boolean setDaemon, int threadPrio) {\n        super(qs.getSchedulerThreadGroup(), qsRsrcs.getThreadName());\n        this.qs = qs;\n        this.qsRsrcs = qsRsrcs;\n        this.setDaemon(setDaemon);\n        if(qsRsrcs.isThreadsInheritInitializersClassLoadContext()) {\n            log.info(\"QuartzSchedulerThread Inheriting ContextClassLoader of thread: {}\", Thread.currentThread().getName());\n            this.setContextClassLoader(Thread.currentThread().getContextClassLoader());\n        }\n\n        this.setPriority(threadPrio);\n\n        // start the underlying thread, but put this object into the 'paused'\n        // state\n        // so processing doesn't start yet...\n        paused = true;\n        halted = new AtomicBoolean(false);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    void setIdleWaitTime(long waitTime) {\n        idleWaitTime = waitTime;\n        idleWaitVariableness = (int) (waitTime * 0.2);\n    }\n\n    private long getRandomizedIdleWaitTime() {\n        return idleWaitTime - random.nextInt(idleWaitVariableness);\n    }\n\n    /**\n     * <p>\n     * Signals the main processing loop to pause at the next possible point.\n     * </p>\n     */\n    void togglePause(boolean pause) {\n        synchronized (sigLock) {\n            paused = pause;\n\n            if (paused) {\n                signalSchedulingChange(0);\n            } else {\n                sigLock.notifyAll();\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Signals the main processing loop to pause at the next possible point.\n     * </p>\n     */\n    void halt(boolean wait) {\n        synchronized (sigLock) {\n            halted.set(true);\n\n            if (paused) {\n                sigLock.notifyAll();\n            } else {\n                signalSchedulingChange(0);\n            }\n        }\n        this.interrupt();\n\n        if (wait) {\n            boolean interrupted = false;\n            try {\n                while (true) {\n                    try {\n                        join();\n                        break;\n                    } catch (InterruptedException e) {\n                        interrupted = true;\n                    }\n                }\n            } finally {\n                if (interrupted) {\n                    Thread.currentThread().interrupt();\n                }\n            }\n        }\n    }\n\n    boolean isPaused() {\n        return paused;\n    }\n\n    /**\n     * <p>\n     * Signals the main processing loop that a change in scheduling has been\n     * made - in order to interrupt any sleeping that may be occurring while\n     * waiting for the fire time to arrive.\n     * </p>\n     *\n     * @param candidateNewNextFireTime the time (in millis) when the newly scheduled trigger\n     * will fire.  If this method is being called do to some other even (rather\n     * than scheduling a trigger), the caller should pass zero (0).\n     */\n    public void signalSchedulingChange(long candidateNewNextFireTime) {\n        synchronized(sigLock) {\n            signaled = true;\n            signaledNextFireTime = candidateNewNextFireTime;\n            sigLock.notifyAll();\n        }\n    }\n\n    public void clearSignaledSchedulingChange() {\n        synchronized(sigLock) {\n            signaled = false;\n            signaledNextFireTime = 0;\n        }\n    }\n\n    public boolean isScheduleChanged() {\n        synchronized(sigLock) {\n            return signaled;\n        }\n    }\n\n    public long getSignaledNextFireTime() {\n        synchronized(sigLock) {\n            return signaledNextFireTime;\n        }\n    }\n\n    /**\n     * <p>\n     * The main processing loop of the <code>QuartzSchedulerThread</code>.\n     * </p>\n     */\n    @Override\n    public void run() {\n        int acquiresFailed = 0;\n\n        while (!halted.get()) {\n            try {\n                // check if we're supposed to pause...\n                synchronized (sigLock) {\n                    while (paused && !halted.get()) {\n                        try {\n                            // wait until togglePause(false) is called...\n                            sigLock.wait(1000L);\n                        } catch (InterruptedException ignore) {\n                        }\n\n                        // reset failure counter when paused, so that we don't\n                        // wait again after unpausing\n                        acquiresFailed = 0;\n                    }\n\n                    if (halted.get()) {\n                        break;\n                    }\n                }\n\n                // wait a bit, if reading from job store is consistently\n                // failing (e.g. DB is down or restarting)..\n                if (acquiresFailed > 1) {\n                    try {\n                        long delay = computeDelayForRepeatedErrors(qsRsrcs.getJobStore(), acquiresFailed);\n                        Thread.sleep(delay);\n                    } catch (Exception ignore) {\n                    }\n                }\n\n                int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();\n                synchronized (sigLock) {\n                    if (halted.get()) {\n                        break;\n                    }\n                }\n                if(availThreadCount > 0) { // will always be true, due to semantics of blockForAvailableThreads...\n\n                    List<OperableTrigger> triggers;\n\n                    long now = System.currentTimeMillis();\n\n                    clearSignaledSchedulingChange();\n                    try {\n                        triggers = qsRsrcs.getJobStore().acquireNextTriggers(\n                                now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());\n                        acquiresFailed = 0;\n                        if (log.isDebugEnabled())\n                            log.debug(\"batch acquisition of {} triggers\", triggers == null ? 0 : triggers.size());\n                    } catch (JobPersistenceException jpe) {\n                        if (acquiresFailed == 0) {\n                            qs.notifySchedulerListenersError(\n                                \"An error occurred while scanning for the next triggers to fire.\",\n                                jpe);\n                        }\n                        if (acquiresFailed < Integer.MAX_VALUE)\n                            acquiresFailed++;\n                        continue;\n                    } catch (RuntimeException e) {\n                        if (acquiresFailed == 0) {\n                            getLog().error(\"quartzSchedulerThreadLoop: RuntimeException {}\", e.getMessage(), e);\n                        }\n                        if (acquiresFailed < Integer.MAX_VALUE)\n                            acquiresFailed++;\n                        continue;\n                    }\n\n                    if (triggers != null && !triggers.isEmpty()) {\n\n                        now = System.currentTimeMillis();\n                        long triggerTime = triggers.get(0).getNextFireTime().getTime();\n                        long timeUntilTrigger = triggerTime - now;\n                        while(timeUntilTrigger > 2) {\n                            synchronized (sigLock) {\n                                if (halted.get()) {\n                                    break;\n                                }\n                                if (!isCandidateNewTimeEarlierWithinReason(triggerTime, false)) {\n                                    try {\n                                        // we could have blocked a long while\n                                        // on 'synchronize', so we must recompute\n                                        now = System.currentTimeMillis();\n                                        timeUntilTrigger = triggerTime - now;\n                                        if(timeUntilTrigger >= 1)\n                                            sigLock.wait(timeUntilTrigger);\n                                    } catch (InterruptedException ignore) {\n                                    }\n                                }\n                            }\n                            synchronized (sigLock) {\n                                if (halted.get()) {\n                                    break;\n                                }\n                            }\n                            if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) {\n                                break;\n                            }\n                            now = System.currentTimeMillis();\n                            timeUntilTrigger = triggerTime - now;\n                        }\n\n                        // this happens if releaseIfScheduleChangedSignificantly decided to release triggers\n                        if(triggers.isEmpty())\n                            continue;\n\n                        // set triggers to 'executing'\n                        List<TriggerFiredResult> bundles = new ArrayList<>();\n\n                        boolean goAhead;\n                        synchronized(sigLock) {\n                            goAhead = !halted.get();\n                        }\n                        if(goAhead) {\n                            try {\n                                List<TriggerFiredResult> res = qsRsrcs.getJobStore().triggersFired(triggers);\n                                if(res != null)\n                                    bundles = res;\n                            } catch (SchedulerException se) {\n                                qs.notifySchedulerListenersError(\n                                        \"An error occurred while firing triggers '\"\n                                                + triggers + \"'\", se);\n                                //QTZ-179 : a problem occurred interacting with the triggers from the db\n                                //we release them and loop again\n                                for (OperableTrigger trigger : triggers) {\n                                    qsRsrcs.getJobStore().releaseAcquiredTrigger(trigger);\n                                }\n                                continue;\n                            }\n\n                        }\n\n                        for (int i = 0; i < bundles.size(); i++) {\n                            TriggerFiredResult result =  bundles.get(i);\n                            TriggerFiredBundle bundle =  result.getTriggerFiredBundle();\n                            Exception exception = result.getException();\n\n                            if (exception instanceof RuntimeException) {\n                                getLog().error(\"RuntimeException while firing trigger {}\", triggers.get(i), exception);\n                                qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));\n                                continue;\n                            }\n\n                            // it's possible to get 'null' if the triggers was paused,\n                            // blocked, or other similar occurrences that prevent it being\n                            // fired at this time...  or if the scheduler was shutdown (halted)\n                            if (bundle == null) {\n                                qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));\n                                continue;\n                            }\n\n                            JobRunShell shell;\n                            try {\n                                shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bundle);\n                                shell.initialize(qs);\n                            } catch (SchedulerException se) {\n                                qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bundle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);\n                                continue;\n                            }\n\n                            if (!qsRsrcs.getThreadPool().runInThread(shell)) {\n                                // this case should never happen, as it is indicative of the\n                                // scheduler being shutdown or a bug in the thread pool or\n                                // a thread pool being used concurrently - which the docs\n                                // say not to do...\n                                getLog().error(\"ThreadPool.runInThread() return false!\");\n                                qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bundle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);\n                            }\n\n                        }\n\n                        continue; // while (!halted)\n                    }\n                } else { // if(availThreadCount > 0)\n                    // should never happen, if threadPool.blockForAvailableThreads() follows contract\n                    continue; // while (!halted)\n                }\n\n                long now = System.currentTimeMillis();\n                long waitTime = now + getRandomizedIdleWaitTime();\n                long timeUntilContinue = waitTime - now;\n                synchronized(sigLock) {\n                    try {\n                      if(!halted.get()) {\n                        // QTZ-336 A job might have been completed in the mean time and we might have\n                        // missed the scheduled changed signal by not waiting for the notify() yet\n                        // Check that before waiting for too long in case this very job needs to be\n                        // scheduled very soon\n                        if (!isScheduleChanged()) {\n                          sigLock.wait(timeUntilContinue);\n                        }\n                      }\n                    } catch (InterruptedException ignore) {\n                    }\n                }\n\n            } catch(RuntimeException re) {\n                getLog().error(\"Runtime error occurred in main trigger firing loop.\", re);\n            }\n        } // while (!halted)\n\n        // drop references to scheduler stuff to aid garbage collection...\n        qs = null;\n        qsRsrcs = null;\n    }\n\n    private static final long MIN_DELAY = 20;\n    private static final long MAX_DELAY = 600000;\n\n    private static long computeDelayForRepeatedErrors(JobStore jobStore, int acquiresFailed) {\n        long delay;\n        try {\n            delay = jobStore.getAcquireRetryDelay(acquiresFailed);\n        } catch (Exception ignored) {\n            // we're trying to be useful in case of error states, not cause\n            // additional errors..\n            delay = 100;\n        }\n\n\n        // sanity check per getAcquireRetryDelay specification\n        if (delay < MIN_DELAY)\n            delay = MIN_DELAY;\n        if (delay > MAX_DELAY)\n            delay = MAX_DELAY;\n\n        return delay;\n    }\n\n    private boolean releaseIfScheduleChangedSignificantly(\n            List<OperableTrigger> triggers, long triggerTime) {\n        if (isCandidateNewTimeEarlierWithinReason(triggerTime, true)) {\n            // above call does a clearSignaledSchedulingChange()\n            for (OperableTrigger trigger : triggers) {\n                qsRsrcs.getJobStore().releaseAcquiredTrigger(trigger);\n            }\n            triggers.clear();\n            return true;\n        }\n        return false;\n    }\n\n    private boolean isCandidateNewTimeEarlierWithinReason(long oldTime, boolean clearSignal) {\n\n        // So here's the deal: We know due to being signaled that 'the schedule'\n        // has changed.  We may know (if getSignaledNextFireTime() != 0) the\n        // new earliest fire time.  We may not (in which case we will assume\n        // that the new time is earlier than the trigger we have acquired).\n        // In either case, we only want to abandon our acquired trigger and\n        // go looking for a new one if \"it's worth it\".  It's only worth it if\n        // the time cost incurred to abandon the trigger and acquire a new one\n        // is less than the time until the currently acquired trigger will fire,\n        // otherwise we're just \"thrashing\" the job store (e.g. database).\n        //\n        // So the question becomes when is it \"worth it\"?  This will depend on\n        // the job store implementation (and of course the particular database\n        // or whatever behind it).  Ideally we would depend on the job store\n        // implementation to tell us the amount of time in which it \"thinks\"\n        // it can abandon the acquired trigger and acquire a new one.  However\n        // we have no current facility for having it tell us that, so we make\n        // a somewhat educated but arbitrary guess ;-).\n\n        synchronized(sigLock) {\n\n            if (!isScheduleChanged())\n                return false;\n\n            boolean earlier = false;\n\n            if(getSignaledNextFireTime() == 0)\n                earlier = true;\n            else if(getSignaledNextFireTime() < oldTime )\n                earlier = true;\n\n            if(earlier) {\n                // so the new time is considered earlier, but is it enough earlier?\n                long diff = oldTime - System.currentTimeMillis();\n                if(diff < (qsRsrcs.getJobStore().supportsPersistence() ? 70L : 7L))\n                    earlier = false;\n            }\n\n            if(clearSignal) {\n                clearSignaledSchedulingChange();\n            }\n\n            return earlier;\n        }\n    }\n\n    public Logger getLog() {\n        return log;\n    }\n\n} // end of QuartzSchedulerThread\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/RemotableQuartzScheduler.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.core;\n\nimport java.rmi.Remote;\nimport java.rmi.RemoteException;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.UnableToInterruptJobException;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * @author James House\n */\npublic interface RemotableQuartzScheduler extends Remote {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    String getSchedulerName() throws RemoteException;\n\n    String getSchedulerInstanceId() throws RemoteException;\n\n    SchedulerContext getSchedulerContext() throws SchedulerException, RemoteException;\n\n    void start() throws SchedulerException, RemoteException;\n\n    void startDelayed(int seconds) throws SchedulerException, RemoteException;\n    \n    void standby() throws RemoteException;\n\n    boolean isInStandbyMode() throws RemoteException;\n\n    void shutdown() throws RemoteException;\n\n    void shutdown(boolean waitForJobsToComplete) throws RemoteException;\n\n    boolean isShutdown() throws RemoteException;\n\n    Date runningSince() throws RemoteException;\n\n    String getVersion() throws RemoteException;\n\n    int numJobsExecuted() throws RemoteException;\n\n    Class<?> getJobStoreClass() throws RemoteException;\n\n    boolean supportsPersistence() throws RemoteException;\n\n    boolean isClustered() throws RemoteException;\n\n    Class<?> getThreadPoolClass() throws RemoteException;\n\n    int getThreadPoolSize() throws RemoteException;\n\n    void clear() throws SchedulerException, RemoteException;\n    \n    List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException, RemoteException;\n\n    Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException, RemoteException;\n\n    Date scheduleJob(Trigger trigger) throws SchedulerException, RemoteException;\n\n    void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException, RemoteException;\n\n    void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException, RemoteException;\n\n    boolean deleteJob(JobKey jobKey) throws SchedulerException, RemoteException;\n\n    boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException, RemoteException;\n        \n    void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException, RemoteException;\n\n    void triggerJob(OperableTrigger trig) throws SchedulerException, RemoteException;\n    \n    void pauseTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException, RemoteException;\n\n    void pauseJob(JobKey jobKey) throws SchedulerException, RemoteException;\n\n    void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException, RemoteException;\n\n    void resumeTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException, RemoteException;\n\n    Set<String> getPausedTriggerGroups() throws SchedulerException, RemoteException;\n    \n    void resumeJob(JobKey jobKey) throws SchedulerException, RemoteException;\n\n    void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException, RemoteException;\n\n    void pauseAll() throws SchedulerException, RemoteException;\n\n    void resumeAll() throws SchedulerException, RemoteException;\n\n    List<String> getJobGroupNames() throws SchedulerException, RemoteException;\n\n    Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException, RemoteException;\n\n    List<? extends Trigger> getTriggersOfJob(JobKey jobKey) throws SchedulerException, RemoteException;\n\n    List<String> getTriggerGroupNames() throws SchedulerException, RemoteException;\n\n    Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException, RemoteException;\n\n    JobDetail getJobDetail(JobKey jobKey) throws SchedulerException, RemoteException;\n\n    List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher) throws SchedulerException, RemoteException;\n\n    Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    void resetTriggerFromErrorState(TriggerKey triggerKey) throws SchedulerException, RemoteException;\n\n    void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException, RemoteException;\n\n    boolean deleteCalendar(String calName) throws SchedulerException, RemoteException;\n\n    Calendar getCalendar(String calName) throws SchedulerException, RemoteException;\n\n    List<String> getCalendarNames() throws SchedulerException, RemoteException;\n\n    boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException,RemoteException;\n\n    boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException,RemoteException;\n    \n    boolean checkExists(JobKey jobKey) throws SchedulerException,RemoteException; \n   \n    boolean checkExists(TriggerKey triggerKey) throws SchedulerException,RemoteException;\n \n    boolean deleteJobs(List<JobKey> jobKeys) throws SchedulerException,RemoteException;\n\n    void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException,RemoteException;\n\n    void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException,RemoteException;\n\n    boolean unscheduleJobs(List<TriggerKey> triggerKeys) throws SchedulerException,RemoteException;\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/SampledStatistics.java",
    "content": "package org.quartz.core;\n\npublic interface SampledStatistics {\n    long getJobsScheduledMostRecentSample();\n    long getJobsExecutingMostRecentSample();\n    long getJobsCompletedMostRecentSample();\n    void shutdown();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/SampledStatisticsImpl.java",
    "content": "package org.quartz.core;\n\nimport java.util.Timer;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobListener;\nimport org.quartz.SchedulerListener;\nimport org.quartz.Trigger;\nimport org.quartz.listeners.SchedulerListenerSupport;\nimport org.quartz.utils.counter.CounterConfig;\nimport org.quartz.utils.counter.CounterManager;\nimport org.quartz.utils.counter.CounterManagerImpl;\nimport org.quartz.utils.counter.sampled.SampledCounter;\nimport org.quartz.utils.counter.sampled.SampledCounterConfig;\nimport org.quartz.utils.counter.sampled.SampledRateCounterConfig;\n\npublic class SampledStatisticsImpl extends SchedulerListenerSupport implements SampledStatistics, JobListener, SchedulerListener {\n    @SuppressWarnings(\"unused\")\n    private final QuartzScheduler scheduler;\n    \n    private static final String NAME = \"QuartzSampledStatistics\";\n    \n    private static final int DEFAULT_HISTORY_SIZE = 30;\n    private static final int DEFAULT_INTERVAL_SECS = 1;\n    private final static SampledCounterConfig DEFAULT_SAMPLED_COUNTER_CONFIG = new SampledCounterConfig(DEFAULT_INTERVAL_SECS,\n            DEFAULT_HISTORY_SIZE, true, 0L);\n    @SuppressWarnings(\"unused\")\n    private final static SampledRateCounterConfig DEFAULT_SAMPLED_RATE_COUNTER_CONFIG = new SampledRateCounterConfig(DEFAULT_INTERVAL_SECS,\n            DEFAULT_HISTORY_SIZE, true);\n\n    private final CounterManager counterManager;\n    private final SampledCounter jobsScheduledCount;\n    private final SampledCounter jobsExecutingCount;\n    private final SampledCounter jobsCompletedCount;\n    \n    SampledStatisticsImpl(QuartzScheduler scheduler) {\n        this.scheduler = scheduler;\n        \n        counterManager = new CounterManagerImpl(new Timer(NAME+\"Timer\"));\n        jobsScheduledCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);\n        jobsExecutingCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);\n        jobsCompletedCount = createSampledCounter(DEFAULT_SAMPLED_COUNTER_CONFIG);\n        \n        scheduler.addInternalSchedulerListener(this);\n        scheduler.addInternalJobListener(this);\n    }\n    \n    public void shutdown() {\n        counterManager.shutdown(true);\n    }\n    \n    private SampledCounter createSampledCounter(CounterConfig defaultCounterConfig) {\n        return (SampledCounter) counterManager.createCounter(defaultCounterConfig);\n    }\n    \n    /**\n     * Clears the collected statistics. Resets all counters to zero\n     */\n    public void clearStatistics() {\n        jobsScheduledCount.getAndReset();\n        jobsExecutingCount.getAndReset();\n        jobsCompletedCount.getAndReset();\n    }\n    \n    public long getJobsCompletedMostRecentSample() {\n        return jobsCompletedCount.getMostRecentSample().getCounterValue();\n    }\n\n    public long getJobsExecutingMostRecentSample() {\n        return jobsExecutingCount.getMostRecentSample().getCounterValue();\n    }\n\n    public long getJobsScheduledMostRecentSample() {\n        return jobsScheduledCount.getMostRecentSample().getCounterValue();\n    }\n\n    public String getName() {\n        return NAME;\n    }\n\n    @Override\n    public void jobScheduled(Trigger trigger) {\n        jobsScheduledCount.increment();\n    }\n    \n    public void jobExecutionVetoed(JobExecutionContext context) {\n        /**/\n    }\n\n    public void jobToBeExecuted(JobExecutionContext context) {\n        jobsExecutingCount.increment();\n    }\n\n    public void jobWasExecuted(JobExecutionContext context,\n            JobExecutionException jobException) {\n        jobsCompletedCount.increment();\n    }\n\n    @Override\n    public void jobAdded(JobDetail jobDetail) {\n        /**/\n    }\n\n    public void jobDeleted(String jobName, String groupName) {\n        /**/\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/SchedulerSignalerImpl.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.core;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.spi.SchedulerSignaler;\n\n/**\n * An interface to be used by <code>JobStore</code> instances in order to\n * communicate signals back to the <code>QuartzScheduler</code>.\n * \n * @author jhouse\n */\npublic class SchedulerSignalerImpl implements SchedulerSignaler {\n\n    final Logger log = LoggerFactory.getLogger(SchedulerSignalerImpl.class);\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected final QuartzScheduler sched;\n    protected final QuartzSchedulerThread schedThread;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public SchedulerSignalerImpl(QuartzScheduler sched, QuartzSchedulerThread schedThread) {\n        this.sched = sched;\n        this.schedThread = schedThread;\n\n        log.info(\"Initialized Scheduler Signaller of type: {}\", getClass());\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void notifyTriggerListenersMisfired(Trigger trigger) {\n        try {\n            sched.notifyTriggerListenersMisfired(trigger);\n        } catch (SchedulerException se) {\n            sched.getLog().error(\n                    \"Error notifying listeners of trigger misfire.\", se);\n            sched.notifySchedulerListenersError(\n                    \"Error notifying listeners of trigger misfire.\", se);\n        }\n    }\n\n    public void notifySchedulerListenersFinalized(Trigger trigger) {\n        sched.notifySchedulerListenersFinalized(trigger);\n    }\n\n    public void signalSchedulingChange(long candidateNewNextFireTime) {\n        schedThread.signalSchedulingChange(candidateNewNextFireTime);\n    }\n\n    public void notifySchedulerListenersJobDeleted(JobKey jobKey) {\n        sched.notifySchedulerListenersJobDeleted(jobKey);\n    }\n\n    public void notifySchedulerListenersError(String string, SchedulerException jpe) {\n        sched.notifySchedulerListenersError(string, jpe);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/CronTriggerSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.STRING;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimeZone;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.CronTrigger;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\npublic class CronTriggerSupport {\n    private static final String COMPOSITE_TYPE_NAME = \"CronTrigger\";\n    private static final String COMPOSITE_TYPE_DESCRIPTION = \"CronTrigger Details\";\n    private static final String[] ITEM_NAMES = new String[] { \"expression\", \"timeZone\" };\n    private static final String[] ITEM_DESCRIPTIONS = new String[] { \"expression\", \"timeZone\" };\n    private static final OpenType[] ITEM_TYPES = new OpenType[] { STRING, STRING };\n    private static final CompositeType COMPOSITE_TYPE;\n    private static final String TABULAR_TYPE_NAME = \"CronTrigger collection\";\n    private static final String TABULAR_TYPE_DESCRIPTION = \"CronTrigger collection\";\n    private static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            COMPOSITE_TYPE = new CompositeType(COMPOSITE_TYPE_NAME,\n                    COMPOSITE_TYPE_DESCRIPTION, getItemNames(), getItemDescriptions(),\n                    getItemTypes());\n            TABULAR_TYPE = new TabularType(TABULAR_TYPE_NAME,\n                    TABULAR_TYPE_DESCRIPTION, COMPOSITE_TYPE, getItemNames());\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    public static String[] getItemNames() {\n        List<String> l = new ArrayList<>(Arrays.asList(ITEM_NAMES));\n        l.addAll(Arrays.asList(TriggerSupport.getItemNames()));\n        return l.toArray(new String[l.size()]);\n    }\n\n    public static String[] getItemDescriptions() {\n        List<String> l = new ArrayList<>(Arrays.asList(ITEM_DESCRIPTIONS));\n        l.addAll(Arrays.asList(TriggerSupport.getItemDescriptions()));\n        return l.toArray(new String[l.size()]);\n    }\n    \n    public static OpenType[] getItemTypes() {\n        List<OpenType> l = new ArrayList<>(Arrays.asList(ITEM_TYPES));\n        l.addAll(Arrays.asList(TriggerSupport.getItemTypes()));\n        return l.toArray(new OpenType[l.size()]);\n    }\n    \n    public static CompositeData toCompositeData(CronTrigger trigger) {\n        try {\n            return new CompositeDataSupport(COMPOSITE_TYPE, ITEM_NAMES,\n                    new Object[] {\n                            trigger.getCronExpression(),\n                            trigger.getTimeZone(),\n                            trigger.getKey().getName(),\n                            trigger.getKey().getGroup(),\n                            trigger.getJobKey().getName(),\n                            trigger.getJobKey().getGroup(),\n                            trigger.getDescription(),\n                            JobDataMapSupport.toTabularData(trigger\n                                    .getJobDataMap()),\n                            trigger.getCalendarName(),\n                            ((OperableTrigger)trigger).getFireInstanceId(),\n                            trigger.getMisfireInstruction(),\n                            trigger.getPriority(), trigger.getStartTime(),\n                            trigger.getEndTime(), trigger.getNextFireTime(),\n                            trigger.getPreviousFireTime(),\n                            trigger.getFinalFireTime() });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static TabularData toTabularData(List<? extends CronTrigger> triggers) {\n        TabularData tData = new TabularDataSupport(TABULAR_TYPE);\n        if (triggers != null) {\n            ArrayList<CompositeData> list = new ArrayList<>();\n            for (CronTrigger trigger : triggers) {\n                list.add(toCompositeData(trigger));\n            }\n            tData.putAll(list.toArray(new CompositeData[list.size()]));\n        }\n        return tData;\n    }\n    \n    public static OperableTrigger newTrigger(CompositeData cData) throws ParseException {\n        CronTriggerImpl result = new CronTriggerImpl();\n        result.setCronExpression((String) cData.get(\"cronExpression\"));\n        if(cData.containsKey(\"timeZone\")) {\n            result.setTimeZone(TimeZone.getTimeZone((String)cData.get(\"timeZone\")));\n        }\n        TriggerSupport.initializeTrigger(result, cData);\n        return result;\n    }\n\n    public static OperableTrigger newTrigger(Map<String, Object> attrMap) throws ParseException {\n        CronTriggerImpl result = new CronTriggerImpl();\n        result.setCronExpression((String) attrMap.get(\"cronExpression\"));\n        if(attrMap.containsKey(\"timeZone\")) {\n            result.setTimeZone(TimeZone.getTimeZone((String)attrMap.get(\"timeZone\")));\n        }\n        TriggerSupport.initializeTrigger(result, attrMap);\n        return result;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/JobDataMapSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.STRING;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.JobDataMap;\n\npublic class JobDataMapSupport {\n    private static final String TYPE_NAME = \"JobDataMap\";\n    private static final String[] keyValue = new String[] { \"key\", \"value\" };\n    private static final OpenType[] openTypes = new OpenType[] { STRING, STRING };\n    private static final CompositeType rowType;\n    public static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            rowType = new CompositeType(TYPE_NAME, TYPE_NAME, keyValue, keyValue,\n                    openTypes);\n            TABULAR_TYPE = new TabularType(TYPE_NAME, TYPE_NAME, rowType,\n                    new String[] { \"key\" });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static JobDataMap newJobDataMap(TabularData tabularData) {\n        JobDataMap jobDataMap = new JobDataMap();\n\n        if(tabularData != null) {\n            for (Object o : tabularData.values()) {\n                CompositeData cData = (CompositeData) o;\n                jobDataMap.put((String) cData.get(\"key\"), (String) cData.get(\"value\"));\n            }\n        }\n        \n        return jobDataMap;\n    }\n\n    public static JobDataMap newJobDataMap(Map<String, Object> map) {\n        JobDataMap jobDataMap = new JobDataMap();\n\n        if (map != null) {\n            jobDataMap.putAll(map);\n        }\n\n        return jobDataMap;\n    }\n    \n    /**\n     * @return composite data\n     */\n    public static CompositeData toCompositeData(String key, String value) {\n        try {\n            return new CompositeDataSupport(rowType, keyValue, new Object[] {\n                    key, value });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * @param jobDataMap\n     * @return TabularData\n     */\n    public static TabularData toTabularData(JobDataMap jobDataMap) {\n        TabularData tData = new TabularDataSupport(TABULAR_TYPE);\n        ArrayList<CompositeData> list = new ArrayList<>();\n        for (Map.Entry<String, Object> entry : jobDataMap.entrySet()) {\n            list.add(toCompositeData(entry.getKey(), String.valueOf(entry.getValue())));\n        }\n        tData.putAll(list.toArray(new CompositeData[list.size()]));\n        return tData;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/JobDetailSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.BOOLEAN;\nimport static javax.management.openmbean.SimpleType.STRING;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.impl.JobDetailImpl;\n\npublic class JobDetailSupport {\n    private static final String COMPOSITE_TYPE_NAME = \"JobDetail\";\n    private static final String COMPOSITE_TYPE_DESCRIPTION = \"Job Execution Details\";\n    private static final String[] ITEM_NAMES = new String[] { \"name\", \"group\",\n            \"description\", \"jobClass\", \"jobDataMap\", \"durability\", \"shouldRecover\",};\n    private static final String[] ITEM_DESCRIPTIONS = new String[] { \"name\",\n            \"group\", \"description\", \"jobClass\", \"jobDataMap\", \"durability\", \"shouldRecover\",};\n    private static final OpenType[] ITEM_TYPES = new OpenType[] { STRING,\n            STRING, STRING, STRING, JobDataMapSupport.TABULAR_TYPE, BOOLEAN,\n            BOOLEAN, };\n    private static final CompositeType COMPOSITE_TYPE;\n    private static final String TABULAR_TYPE_NAME = \"JobDetail collection\";\n    private static final String TABULAR_TYPE_DESCRIPTION = \"JobDetail collection\";\n    private static final String[] INDEX_NAMES = new String[] { \"name\", \"group\" };\n    private static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            COMPOSITE_TYPE = new CompositeType(COMPOSITE_TYPE_NAME,\n                    COMPOSITE_TYPE_DESCRIPTION, ITEM_NAMES, ITEM_DESCRIPTIONS,\n                    ITEM_TYPES);\n            TABULAR_TYPE = new TabularType(TABULAR_TYPE_NAME,\n                    TABULAR_TYPE_DESCRIPTION, COMPOSITE_TYPE, INDEX_NAMES);\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * @param cData\n     * @return JobDetail\n     */\n    public static JobDetail newJobDetail(CompositeData cData)\n      throws ClassNotFoundException\n    {\n        JobDetailImpl jobDetail = new JobDetailImpl();\n\n        int i = 0;\n        jobDetail.setName((String) cData.get(ITEM_NAMES[i++]));\n        jobDetail.setGroup((String) cData.get(ITEM_NAMES[i++]));\n        jobDetail.setDescription((String) cData.get(ITEM_NAMES[i++]));\n        Class<?> jobClass = Class.forName((String) cData.get(ITEM_NAMES[i++]));\n        @SuppressWarnings(\"unchecked\")\n        Class<? extends Job> jobClassTyped = (Class<? extends Job>)jobClass;\n        jobDetail.setJobClass(jobClassTyped);\n        jobDetail.setJobDataMap(JobDataMapSupport.newJobDataMap((TabularData) cData.get(ITEM_NAMES[i++])));\n        jobDetail.setDurability((Boolean) cData.get(ITEM_NAMES[i++]));\n        jobDetail.setRequestsRecovery((Boolean) cData.get(ITEM_NAMES[i++]));\n\n        return jobDetail;\n    }\n\n    /**\n     * @param attrMap the attributes that define the job\n     * @return JobDetail\n     */\n    public static JobDetail newJobDetail(Map<String, Object> attrMap)\n        throws ClassNotFoundException\n    {\n        JobDetailImpl jobDetail = new JobDetailImpl();\n\n        int i = 0;\n        jobDetail.setName((String) attrMap.get(ITEM_NAMES[i++]));\n        jobDetail.setGroup((String) attrMap.get(ITEM_NAMES[i++]));\n        jobDetail.setDescription((String) attrMap.get(ITEM_NAMES[i++]));\n        Class<?> jobClass = Class.forName((String) attrMap.get(ITEM_NAMES[i++]));\n        @SuppressWarnings(\"unchecked\")\n        Class<? extends Job> jobClassTyped = (Class<? extends Job>)jobClass;\n        jobDetail.setJobClass(jobClassTyped);\n        if(attrMap.containsKey(ITEM_NAMES[i])) {\n            @SuppressWarnings(\"unchecked\")\n            Map<String, Object> map = (Map<String, Object>)attrMap.get(ITEM_NAMES[i]); \n            jobDetail.setJobDataMap(JobDataMapSupport.newJobDataMap(map));\n        }\n        i++;\n        if(attrMap.containsKey(ITEM_NAMES[i])) {\n            jobDetail.setDurability((Boolean) attrMap.get(ITEM_NAMES[i]));\n        }\n        i++;\n        if(attrMap.containsKey(ITEM_NAMES[i])) {\n            jobDetail.setRequestsRecovery((Boolean) attrMap.get(ITEM_NAMES[i]));\n        }\n        i++;\n        \n        return jobDetail;\n    }\n    \n    /**\n     * @param jobDetail\n     * @return CompositeData\n     */\n    public static CompositeData toCompositeData(JobDetail jobDetail) {\n        try {\n            return new CompositeDataSupport(COMPOSITE_TYPE, ITEM_NAMES,\n                    new Object[] {\n                            jobDetail.getKey().getName(),\n                            jobDetail.getKey().getGroup(),\n                            jobDetail.getDescription(),\n                            jobDetail.getJobClass().getName(),\n                            JobDataMapSupport.toTabularData(jobDetail\n                                    .getJobDataMap()), \n                            jobDetail.isDurable(),\n                            jobDetail.requestsRecovery(), });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static TabularData toTabularData(JobDetail[] jobDetails) {\n        TabularData tData = new TabularDataSupport(TABULAR_TYPE);\n        if (jobDetails != null) {\n            ArrayList<CompositeData> list = new ArrayList<>();\n            for (JobDetail jobDetail : jobDetails) {\n                list.add(toCompositeData(jobDetail));\n            }\n            tData.putAll(list.toArray(new CompositeData[list.size()]));\n        }\n        return tData;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/JobExecutionContextSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.BOOLEAN;\nimport static javax.management.openmbean.SimpleType.DATE;\nimport static javax.management.openmbean.SimpleType.INTEGER;\nimport static javax.management.openmbean.SimpleType.LONG;\nimport static javax.management.openmbean.SimpleType.STRING;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.SchedulerException;\n\npublic class JobExecutionContextSupport {\n    private static final String COMPOSITE_TYPE_NAME = \"JobExecutionContext\";\n    private static final String COMPOSITE_TYPE_DESCRIPTION = \"Job Execution Instance Details\";\n    private static final String[] ITEM_NAMES = new String[] { \"schedulerName\",\n            \"triggerName\", \"triggerGroup\", \"jobName\", \"jobGroup\", \"jobDataMap\",\n            \"calendarName\", \"recovering\", \"refireCount\", \"fireTime\",\n            \"scheduledFireTime\", \"previousFireTime\", \"nextFireTime\",\n            \"jobRunTime\", \"fireInstanceId\" };\n    private static final String[] ITEM_DESCRIPTIONS = new String[] {\n            \"schedulerName\", \"triggerName\", \"triggerGroup\", \"jobName\",\n            \"jobGroup\", \"jobDataMap\", \"calendarName\", \"recovering\",\n            \"refireCount\", \"fireTime\", \"scheduledFireTime\", \"previousFireTime\",\n            \"nextFireTime\", \"jobRunTime\", \"fireInstanceId\" };\n    private static final OpenType[] ITEM_TYPES = new OpenType[] { STRING,\n            STRING, STRING, STRING, STRING, JobDataMapSupport.TABULAR_TYPE,\n            STRING, BOOLEAN, INTEGER, DATE, DATE, DATE, DATE, LONG, STRING };\n    private static final CompositeType COMPOSITE_TYPE;\n    private static final String TABULAR_TYPE_NAME = \"JobExecutionContextArray\";\n    private static final String TABULAR_TYPE_DESCRIPTION = \"Array of composite JobExecutionContext\";\n    private static final String[] INDEX_NAMES = new String[] { \"schedulerName\",\n            \"triggerName\", \"triggerGroup\", \"jobName\", \"jobGroup\", \"fireTime\" };\n    private static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            COMPOSITE_TYPE = new CompositeType(COMPOSITE_TYPE_NAME,\n                    COMPOSITE_TYPE_DESCRIPTION, ITEM_NAMES, ITEM_DESCRIPTIONS,\n                    ITEM_TYPES);\n            TABULAR_TYPE = new TabularType(TABULAR_TYPE_NAME,\n                    TABULAR_TYPE_DESCRIPTION, COMPOSITE_TYPE, INDEX_NAMES);\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * @return composite data\n     */\n    public static CompositeData toCompositeData(JobExecutionContext jec)\n            throws SchedulerException {\n        try {\n            return new CompositeDataSupport(COMPOSITE_TYPE, ITEM_NAMES,\n                    new Object[] {\n                            jec.getScheduler().getSchedulerName(),\n                            jec.getTrigger().getKey().getName(),\n                            jec.getTrigger().getKey().getGroup(),\n                            jec.getJobDetail().getKey().getName(),\n                            jec.getJobDetail().getKey().getGroup(),\n                            JobDataMapSupport.toTabularData(jec\n                                    .getMergedJobDataMap()),\n                            jec.getTrigger().getCalendarName(),\n                            jec.isRecovering(),\n                            jec.getRefireCount(),\n                            jec.getFireTime(), jec.getScheduledFireTime(),\n                            jec.getPreviousFireTime(), jec.getNextFireTime(),\n                            jec.getJobRunTime(),\n                            jec.getFireInstanceId() });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * @return array of region statistics\n     */\n    public static TabularData toTabularData(\n            final List<JobExecutionContext> executingJobs)\n            throws SchedulerException {\n        List<CompositeData> list = new ArrayList<>();\n        for (JobExecutionContext executingJob : executingJobs) {\n            list.add(toCompositeData(executingJob));\n        }\n        TabularData td = new TabularDataSupport(TABULAR_TYPE);\n        td.putAll(list.toArray(new CompositeData[list.size()]));\n        return td;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/QuartzSchedulerMBean.java",
    "content": "package org.quartz.core.jmx;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.TabularData;\n\npublic interface QuartzSchedulerMBean {\n    String SCHEDULER_STARTED = \"schedulerStarted\";\n    String SCHEDULER_PAUSED = \"schedulerPaused\";\n    String SCHEDULER_SHUTDOWN = \"schedulerShutdown\";\n    String SCHEDULER_ERROR = \"schedulerError\";\n\n    String JOB_ADDED = \"jobAdded\";\n    String JOB_DELETED = \"jobDeleted\";\n    String JOB_SCHEDULED = \"jobScheduled\";\n    String JOB_UNSCHEDULED = \"jobUnscheduled\";\n    \n    String JOBS_PAUSED = \"jobsPaused\";\n    String JOBS_RESUMED = \"jobsResumed\";\n\n    String JOB_EXECUTION_VETOED = \"jobExecutionVetoed\";\n    String JOB_TO_BE_EXECUTED = \"jobToBeExecuted\";\n    String JOB_WAS_EXECUTED = \"jobWasExecuted\";\n\n    String TRIGGER_FINALIZED = \"triggerFinalized\";\n\n    String TRIGGERS_PAUSED = \"triggersPaused\";\n    String TRIGGERS_RESUMED = \"triggersResumed\";\n\n    String SCHEDULING_DATA_CLEARED = \"schedulingDataCleared\";\n\n    String SAMPLED_STATISTICS_ENABLED = \"sampledStatisticsEnabled\";\n    String SAMPLED_STATISTICS_RESET = \"sampledStatisticsReset\";\n\n    String getSchedulerName();\n\n    String getSchedulerInstanceId();\n\n    boolean isStandbyMode();\n\n    boolean isShutdown();\n\n    String getVersion();\n\n    String getJobStoreClassName();\n\n    String getThreadPoolClassName();\n\n    int getThreadPoolSize();\n\n    long getJobsScheduledMostRecentSample();\n\n    long getJobsExecutedMostRecentSample();\n\n    long getJobsCompletedMostRecentSample();\n\n    Map<String, Long> getPerformanceMetrics();\n\n    /**\n     * @return TabularData of CompositeData:JobExecutionContext\n     * @throws Exception\n     */\n    TabularData getCurrentlyExecutingJobs() throws Exception;\n\n    /**\n     * @return TabularData of CompositeData:JobDetail\n     * @throws Exception\n     * @see JobDetailSupport\n     */\n    TabularData getAllJobDetails() throws Exception;\n\n    /**\n     * @return List of CompositeData:[CronTrigger|SimpleTrigger]\n     * @throws Exception\n     * @see TriggerSupport\n     */\n    List<CompositeData> getAllTriggers() throws Exception;\n\n    List<String> getJobGroupNames() throws Exception;\n\n    List<String> getJobNames(String groupName)\n            throws Exception;\n\n    /**\n     * @return CompositeData:JobDetail\n     * @throws Exception\n     * @see JobDetailSupport\n     */\n    CompositeData getJobDetail(String jobName, String jobGroupName) throws Exception;\n\n    boolean isStarted();\n\n    void start() throws Exception;\n\n    void shutdown();\n\n    void standby();\n\n    void clear() throws Exception;\n    \n    /**\n     * Schedule an existing job with an existing trigger.\n     * \n     * @param jobName\n     * @param jobGroup\n     * @param triggerName\n     * @param triggerGroup\n     * @return date of nextFireTime\n     * @throws Exception\n     */\n    Date scheduleJob(String jobName, String jobGroup,\n            String triggerName, String triggerGroup) throws Exception;\n\n    /**\n     * Schedules a job using the given Cron/Simple triggerInfo.\n     * \n     * The triggerInfo and jobDetailInfo must contain well-known attribute values.\n     *     TriggerInfo attributes: name, group, description, calendarName, priority,\n     *       CronExpression | (startTime, endTime, repeatCount, repeatInterval) \n     *     JobDetailInfo attributes: name, group, description, jobClass, jobDataMap, durability,\n     *       shouldRecover\n     */\n    void scheduleBasicJob(Map<String, Object> jobDetailInfo, Map<String, Object> triggerInfo)\n            throws Exception;\n\n    /**\n     * Schedules an arbitrary job described by abstractJobInfo using a trigger specified by abstractTriggerInfo.\n     * \n     * AbstractTriggerInfo and AbstractJobInfo must contain the following String attributes.\n     *     AbstractTriggerInfo: triggerClass, the fully-qualified class name of a concrete Trigger type\n     *     AbstractJobInfo: jobDetailClass, the fully-qualified class name of a concrete JobDetail type\n     *\n     * If the Trigger and JobDetail can be successfully instantiated, the remaining attributes will be\n     * reflectively applied to those instances. The remaining attributes are limited to the types:\n     *  <code>Integer, Double, Float, String, Boolean, Date, Character, Map&lt;String, Object&gt;</code>.\n     * Maps are further limited to containing values from the same set of types, less Map itself.\n     * \n     * @throws Exception \n     */\n    void scheduleJob(Map<String, Object> abstractJobInfo,\n            Map<String, Object> abstractTriggerInfo) throws Exception;\n    \n    /**\n     * Schedules the specified job using a trigger described by abstractTriggerInfo, which must contain the\n     * fully-qualified trigger class name under the key \"triggerClass.\"  That trigger type must contain a\n     * no-arg constructor and have public access. Other attributes are applied reflectively and are limited\n     * to the types:\n     *   <code>Integer, Double, Float, String, Boolean, Date, Character, Map&lt;String, Object&gt;.</code>\n     * Maps are limited to containing values from the same set of types, less Map itself.\n     * \n     * @param jobName\n     * @param jobGroup\n     * @param abstractTriggerInfo\n     * @throws Exception\n     */\n    void scheduleJob(String jobName, String jobGroup,\n            Map<String, Object> abstractTriggerInfo) throws Exception;\n    \n    boolean unscheduleJob(String triggerName, String triggerGroup) throws Exception;\n\n    boolean interruptJob(String jobName, String jobGroupName) throws Exception;\n\n    boolean interruptJob(String fireInstanceId) throws Exception;\n    \n    void triggerJob(String jobName, String jobGroupName,\n            Map<String, String> jobDataMap) throws Exception;\n\n    boolean deleteJob(String jobName, String jobGroupName)\n            throws Exception;\n\n    void addJob(CompositeData jobDetail, boolean replace) throws Exception;\n\n    /**\n     * Adds a durable job described by abstractJobInfo, which must contain the fully-qualified JobDetail\n     * class name under the key \"jobDetailClass.\"  That JobDetail type must contain a no-arg constructor\n     * and have public access. Other attributes are applied reflectively and are limited\n     * to the types:\n     *   <code>Integer, Double, Float, String, Boolean, Date, Character, Map&lt;String, Object&gt;.</code>\n     * Maps are limited to containing values from the same set of types, less Map itself.\n     * \n     * @param abstractJobInfo map of attributes defining job\n     * @param replace whether or not to replace a preexisting job with the same key\n     * @throws Exception\n     */\n    void addJob(Map<String, Object> abstractJobInfo, boolean replace)\n            throws Exception;\n\n    void pauseJobGroup(String jobGroup) throws Exception;\n\n    /**\n     * Pause all jobs whose group starts with jobGroupPrefix\n     * @throws Exception\n     */\n    void pauseJobsStartingWith(String jobGroupPrefix) throws Exception;\n\n    /**\n     * Pause all jobs whose group ends with jobGroupSuffix\n     */\n    void pauseJobsEndingWith(String jobGroupSuffix) throws Exception;\n\n    /**\n     * Pause all jobs whose group contains jobGroupToken\n     */\n    void pauseJobsContaining(String jobGroupToken) throws Exception;\n\n    /**\n     * Pause all jobs whose group is anything\n     */\n    void pauseJobsAll() throws Exception;\n\n    /**\n     * Resume all jobs in the given group\n     */\n    void resumeJobGroup(String jobGroup) throws Exception;\n\n    /**\n     * Resume all jobs whose group starts with jobGroupPrefix\n     */\n    void resumeJobsStartingWith(String jobGroupPrefix) throws Exception;\n\n    /**\n     * Resume all jobs whose group ends with jobGroupSuffix\n     */\n    void resumeJobsEndingWith(String jobGroupSuffix) throws Exception;\n\n    /**\n     * Resume all jobs whose group contains jobGroupToken\n     */\n    void resumeJobsContaining(String jobGroupToken) throws Exception;\n\n    /**\n     * Resume all jobs whose group is anything\n     */\n    void resumeJobsAll() throws Exception;\n\n    void pauseJob(String jobName, String groupName) throws Exception;\n\n    void resumeJob(String jobName, String jobGroupName)    throws Exception;\n\n    List<String> getTriggerGroupNames() throws Exception;\n\n    List<String> getTriggerNames(String triggerGroupName) throws Exception;\n\n    CompositeData getTrigger(String triggerName, String triggerGroupName) throws Exception;\n\n    String getTriggerState(String triggerName, String triggerGroupName) throws Exception;\n\n    /**\n     * @return List of CompositeData:[CronTrigger|SimpleTrigger] for the specified job.\n     * @see TriggerSupport\n     */\n    List<CompositeData> getTriggersOfJob(String jobName, String jobGroupName) throws Exception;\n\n    Set<String> getPausedTriggerGroups() throws Exception;\n\n    void pauseAllTriggers() throws Exception;\n\n    void resumeAllTriggers() throws Exception;\n\n    void pauseTriggerGroup(String triggerGroup) throws Exception;\n\n    /**\n     * Pause all triggers whose group starts with triggerGroupPrefix\n     */\n    void pauseTriggersStartingWith(String triggerGroupPrefix) throws Exception;\n\n    /**\n     * Pause all triggers whose group ends with triggerGroupSuffix\n     */\n    void pauseTriggersEndingWith(String suffix) throws Exception;\n\n    /**\n     * Pause all triggers whose group contains triggerGroupToken\n     */\n    void pauseTriggersContaining(String triggerGroupToken) throws Exception;\n\n    /**\n     * Pause all triggers whose group is anything\n     */\n    void pauseTriggersAll() throws Exception;\n\n    void resumeTriggerGroup(String triggerGroup) throws Exception;\n\n    /**\n     * Resume all triggers whose group starts with triggerGroupPrefix\n     */\n    void resumeTriggersStartingWith(String triggerGroupPrefix) throws Exception;\n\n    /**\n     * Resume all triggers whose group ends with triggerGroupSuffix\n     */\n    void resumeTriggersEndingWith(String triggerGroupSuffix) throws Exception;\n\n    /**\n     * Resume all triggers whose group contains triggerGroupToken\n     */\n    void resumeTriggersContaining(String triggerGroupToken) throws Exception;\n\n    /**\n     * Resume all triggers whose group is anything\n     */\n    void resumeTriggersAll() throws Exception;\n\n    void pauseTrigger(String triggerName, String triggerGroupName) throws Exception;\n\n    void resumeTrigger(String triggerName, String triggerGroupName) throws Exception;\n\n    List<String> getCalendarNames() throws Exception;\n\n    void deleteCalendar(String name) throws Exception;\n\n    void setSampledStatisticsEnabled(boolean enabled);\n\n    boolean isSampledStatisticsEnabled();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/SimpleTriggerSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.INTEGER;\nimport static javax.management.openmbean.SimpleType.LONG;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\npublic class SimpleTriggerSupport {\n    private static final String COMPOSITE_TYPE_NAME = \"SimpleTrigger\";\n    private static final String COMPOSITE_TYPE_DESCRIPTION = \"SimpleTrigger Details\";\n    private static final String[] ITEM_NAMES = new String[] { \"repeatCount\", \"repeatInterval\", \"timesTriggered\" };\n    private static final String[] ITEM_DESCRIPTIONS = new String[] { \"repeatCount\", \"repeatInterval\", \"timesTriggered\" };\n    private static final OpenType[] ITEM_TYPES = new OpenType[] { INTEGER, LONG, INTEGER };\n    private static final CompositeType COMPOSITE_TYPE;\n    private static final String TABULAR_TYPE_NAME = \"SimpleTrigger collection\";\n    private static final String TABULAR_TYPE_DESCRIPTION = \"SimpleTrigger collection\";\n    private static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            COMPOSITE_TYPE = new CompositeType(COMPOSITE_TYPE_NAME,\n                    COMPOSITE_TYPE_DESCRIPTION, getItemNames(), getItemDescriptions(),\n                    getItemTypes());\n            TABULAR_TYPE = new TabularType(TABULAR_TYPE_NAME,\n                    TABULAR_TYPE_DESCRIPTION, COMPOSITE_TYPE, getItemNames());\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    public static String[] getItemNames() {\n        List<String> l = new ArrayList<>(Arrays.asList(ITEM_NAMES));\n        l.addAll(Arrays.asList(TriggerSupport.getItemNames()));\n        return l.toArray(new String[l.size()]);\n    }\n\n    public static String[] getItemDescriptions() {\n        List<String> l = new ArrayList<>(Arrays.asList(ITEM_DESCRIPTIONS));\n        l.addAll(Arrays.asList(TriggerSupport.getItemDescriptions()));\n        return l.toArray(new String[l.size()]);\n    }\n    \n    public static OpenType[] getItemTypes() {\n        List<OpenType> l = new ArrayList<>(Arrays.asList(ITEM_TYPES));\n        l.addAll(Arrays.asList(TriggerSupport.getItemTypes()));\n        return l.toArray(new OpenType[l.size()]);\n    }\n    \n    public static CompositeData toCompositeData(SimpleTrigger trigger) {\n        try {\n            return new CompositeDataSupport(COMPOSITE_TYPE, ITEM_NAMES,\n                    new Object[] {\n                            trigger.getRepeatCount(),\n                            trigger.getRepeatInterval(),\n                            trigger.getTimesTriggered(),\n                            trigger.getKey().getName(),\n                            trigger.getKey().getGroup(),\n                            trigger.getJobKey().getName(),\n                            trigger.getJobKey().getGroup(),\n                            trigger.getDescription(),\n                            JobDataMapSupport.toTabularData(trigger\n                                    .getJobDataMap()),\n                            trigger.getCalendarName(),\n                            ((OperableTrigger)trigger).getFireInstanceId(),\n                            trigger.getMisfireInstruction(),\n                            trigger.getPriority(), trigger.getStartTime(),\n                            trigger.getEndTime(), trigger.getNextFireTime(),\n                            trigger.getPreviousFireTime(),\n                            trigger.getFinalFireTime() });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static TabularData toTabularData(List<? extends SimpleTrigger> triggers) {\n        TabularData tData = new TabularDataSupport(TABULAR_TYPE);\n        if (triggers != null) {\n            ArrayList<CompositeData> list = new ArrayList<>();\n            for (SimpleTrigger trigger : triggers) {\n                list.add(toCompositeData(trigger));\n            }\n            tData.putAll(list.toArray(new CompositeData[list.size()]));\n        }\n        return tData;\n    }\n    \n    public static OperableTrigger newTrigger(CompositeData cData) throws ParseException {\n        SimpleTriggerImpl result = new SimpleTriggerImpl();\n        result.setRepeatCount((Integer) cData.get(\"repeatCount\"));\n        result.setRepeatInterval((Long) cData.get(\"repeatInterval\"));\n        result.setTimesTriggered((Integer) cData.get(\"timesTriggered\"));\n        TriggerSupport.initializeTrigger(result, cData);\n        return result;\n    }\n\n    public static OperableTrigger newTrigger(Map<String, Object> attrMap) throws ParseException {\n        SimpleTriggerImpl result = new SimpleTriggerImpl();\n        if(attrMap.containsKey(\"repeatCount\")) {\n            result.setRepeatCount((Integer) attrMap.get(\"repeatCount\"));\n        }\n        if(attrMap.containsKey(\"repeatInterval\")) {\n            result.setRepeatInterval((Long) attrMap.get(\"repeatInterval\"));\n        }\n        if(attrMap.containsKey(\"timesTriggered\")) {\n            result.setTimesTriggered((Integer) attrMap.get(\"timesTriggered\"));\n        }\n        TriggerSupport.initializeTrigger(result, attrMap);\n        return result;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/jmx/TriggerSupport.java",
    "content": "package org.quartz.core.jmx;\n\nimport static javax.management.openmbean.SimpleType.DATE;\nimport static javax.management.openmbean.SimpleType.INTEGER;\nimport static javax.management.openmbean.SimpleType.STRING;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.management.openmbean.CompositeData;\nimport javax.management.openmbean.CompositeDataSupport;\nimport javax.management.openmbean.CompositeType;\nimport javax.management.openmbean.OpenDataException;\nimport javax.management.openmbean.OpenType;\nimport javax.management.openmbean.TabularData;\nimport javax.management.openmbean.TabularDataSupport;\nimport javax.management.openmbean.TabularType;\n\nimport org.quartz.JobKey;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.MutableTrigger;\nimport org.quartz.spi.OperableTrigger;\n\npublic class TriggerSupport {\n    private static final String COMPOSITE_TYPE_NAME = \"Trigger\";\n    private static final String COMPOSITE_TYPE_DESCRIPTION = \"Trigger Details\";\n    private static final String[] ITEM_NAMES = new String[] { \"name\",\n      \"group\", \"jobName\", \"jobGroup\", \"description\", \"jobDataMap\",\n            \"calendarName\", \"fireInstanceId\", \"misfireInstruction\", \"priority\",\n            \"startTime\", \"endTime\", \"nextFireTime\", \"previousFireTime\", \"finalFireTime\" };\n    private static final String[] ITEM_DESCRIPTIONS = new String[] { \"name\",\n            \"group\", \"jobName\", \"jobGroup\", \"description\", \"jobDataMap\",\n            \"calendarName\", \"fireInstanceId\", \"misfireInstruction\", \"priority\",\n      \"startTime\", \"endTime\", \"nextFireTime\", \"previousFireTime\", \"finalFireTime\" };\n    private static final OpenType[] ITEM_TYPES = new OpenType[] { STRING,\n            STRING, STRING, STRING, STRING, JobDataMapSupport.TABULAR_TYPE,\n            STRING, STRING, INTEGER, INTEGER,\n      DATE, DATE, DATE, DATE, DATE };\n    private static final CompositeType COMPOSITE_TYPE;\n    private static final String TABULAR_TYPE_NAME = \"Trigger collection\";\n    private static final String TABULAR_TYPE_DESCRIPTION = \"Trigger collection\";\n    private static final String[] INDEX_NAMES = new String[] { \"name\", \"group\" };\n    private static final TabularType TABULAR_TYPE;\n\n    static {\n        try {\n            COMPOSITE_TYPE = new CompositeType(COMPOSITE_TYPE_NAME,\n                    COMPOSITE_TYPE_DESCRIPTION, ITEM_NAMES, ITEM_DESCRIPTIONS,\n                    ITEM_TYPES);\n            TABULAR_TYPE = new TabularType(TABULAR_TYPE_NAME,\n                    TABULAR_TYPE_DESCRIPTION, COMPOSITE_TYPE, INDEX_NAMES);\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    public static String[] getItemNames() {\n        return ITEM_NAMES;\n    }\n\n    public static String[] getItemDescriptions() {\n        return ITEM_DESCRIPTIONS;\n    }\n    \n    public static OpenType[] getItemTypes() {\n        return ITEM_TYPES;\n    }\n    \n    public String[] getIndexNames() {\n        return INDEX_NAMES;\n    }\n    \n    public static CompositeData toCompositeData(Trigger trigger) {\n        try {\n            return new CompositeDataSupport(COMPOSITE_TYPE, ITEM_NAMES,\n                    new Object[] {\n                            trigger.getKey().getName(),\n                            trigger.getKey().getGroup(),\n                            trigger.getJobKey().getName(),\n                            trigger.getJobKey().getGroup(),\n                            trigger.getDescription(),\n                            JobDataMapSupport.toTabularData(trigger\n                                    .getJobDataMap()),\n                            trigger.getCalendarName(),\n                            ((OperableTrigger)trigger).getFireInstanceId(),\n                            trigger.getMisfireInstruction(),\n                            trigger.getPriority(), trigger.getStartTime(),\n                            trigger.getEndTime(), trigger.getNextFireTime(),\n                            trigger.getPreviousFireTime(),\n                            trigger.getFinalFireTime() });\n        } catch (OpenDataException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static TabularData toTabularData(List<? extends Trigger> triggers) {\n        TabularData tData = new TabularDataSupport(TABULAR_TYPE);\n        if (triggers != null) {\n            ArrayList<CompositeData> list = new ArrayList<>();\n            for (Trigger trigger : triggers) {\n                list.add(toCompositeData(trigger));\n            }\n            tData.putAll(list.toArray(new CompositeData[list.size()]));\n        }\n        return tData;\n    }\n    \n    public static List<CompositeData> toCompositeList(List<? extends Trigger> triggers) {\n        List<CompositeData> result = new ArrayList<>();\n        for(Trigger trigger : triggers) {\n            CompositeData cData = TriggerSupport.toCompositeData(trigger);\n            result.add(cData);\n        }\n        return result;\n    }\n    \n    public static void initializeTrigger(MutableTrigger trigger, CompositeData cData) {\n        trigger.setDescription((String) cData.get(\"description\"));\n        trigger.setCalendarName((String) cData.get(\"calendarName\"));\n        if(cData.containsKey(\"priority\")) {\n            trigger.setPriority((Integer) cData.get(\"priority\"));\n        }\n        if(cData.containsKey(\"jobDataMap\")) {\n            trigger.setJobDataMap(JobDataMapSupport.newJobDataMap((TabularData)cData.get(\"jobDataMap\")));\n        }\n        Date startTime;\n        if(cData.containsKey(\"startTime\")) {\n            startTime = (Date) cData.get(\"startTime\");\n        } else {\n            startTime = new Date();\n        }\n        trigger.setStartTime(startTime);\n        trigger.setEndTime((Date) cData.get(\"endTime\"));\n        if(cData.containsKey(\"misfireInstruction\")) {\n            trigger.setMisfireInstruction((Integer) cData.get(\"misfireInstruction\"));\n        }\n        trigger.setKey(new TriggerKey((String) cData.get(\"name\"), (String) cData.get(\"group\")));\n        trigger.setJobKey(new JobKey((String) cData.get(\"jobName\"), (String) cData.get(\"jobGroup\")));\n    }\n    \n    public static void initializeTrigger(MutableTrigger trigger, Map<String, Object> attrMap) {\n        trigger.setDescription((String) attrMap.get(\"description\"));\n        trigger.setCalendarName((String) attrMap.get(\"calendarName\"));\n        if(attrMap.containsKey(\"priority\")) {\n            trigger.setPriority((Integer) attrMap.get(\"priority\"));\n        }\n        if(attrMap.containsKey(\"jobDataMap\")) {\n            @SuppressWarnings(\"unchecked\") // cast as expected.\n            Map<String, Object> mapTyped = (Map<String, Object>)attrMap.get(\"jobDataMap\");\n            trigger.setJobDataMap(JobDataMapSupport.newJobDataMap(mapTyped));\n        }\n        Date startTime;\n        if(attrMap.containsKey(\"startTime\")) {\n            startTime = (Date) attrMap.get(\"startTime\");\n        } else {\n            startTime = new Date();\n        }\n        trigger.setStartTime(startTime);\n        if(attrMap.containsKey(\"endTime\")) {\n            trigger.setEndTime((Date) attrMap.get(\"endTime\"));\n        }\n        if(attrMap.containsKey(\"misfireInstruction\")) {\n            trigger.setMisfireInstruction((Integer) attrMap.get(\"misfireInstruction\"));\n        }\n        trigger.setKey(new TriggerKey((String) attrMap.get(\"name\"), (String) attrMap.get(\"group\")));\n        trigger.setJobKey(new JobKey((String) attrMap.get(\"jobName\"), (String) attrMap.get(\"jobGroup\")));\n    }\n    \n    public static OperableTrigger newTrigger(CompositeData cData) throws ParseException {\n        OperableTrigger result;\n        if(cData.containsKey(\"cronExpression\")) {\n            result = CronTriggerSupport.newTrigger(cData);\n        } else {\n            result = SimpleTriggerSupport.newTrigger(cData);\n        }\n        return result;\n    }\n    \n    public static OperableTrigger newTrigger(Map<String, Object> attrMap) throws ParseException {\n        OperableTrigger result;\n        if(attrMap.containsKey(\"cronExpression\")) {\n            result = CronTriggerSupport.newTrigger(attrMap);\n        } else {\n            result = SimpleTriggerSupport.newTrigger(attrMap);\n        }\n        return result;\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/mbeans-descriptors.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE mbeans-descriptors PUBLIC \"-//Apache Software Foundation//DTD Model MBeans Configuration File\"\n   \"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd\">\n<mbeans-descriptors>\n\t<mbean name=\"QuartzScheduler\" description=\"A Quartz Scheduler.\" domain=\"quartz\" type=\"org.quartz.core.QuartzScheduler\">\n\t\n\t\t<!-- ATTRIBUTES -->\n\t\t<attribute name=\"schedulerName\" description=\"The name of the scheduler.\" type=\"java.lang.String\" writeable=\"false\"/>\n\t\t<attribute name=\"schedulerInstanceId\" description=\"The instance Id of the scheduler.\" type=\"java.lang.String\" writeable=\"false\"/>\n\t\t<attribute name=\"schedulerContext\" description=\"The SchedulerContext of the scheduler.\" type=\"org.quartz.SchedulerContext\" writeable=\"false\"/>\n\t\t<attribute name=\"inStandbyMode\" description=\"Whether the scheduler is currently in standby (paused).\" type=\"boolean\" writeable=\"false\" is=\"true\"/>\n\t\t<attribute name=\"shutdown\" description=\"Whether the scheduler has been shutdown.\" type=\"boolean\" writeable=\"false\" is=\"true\"/>\n\t\t<attribute name=\"jobFactory\" description=\"The JobFactory that will be responsible for producing instances of Job classes.\" type=\"org.quartz.spi.JobFactory\" readable=\"false\" writeable=\"true\"/>\n\t\t<attribute name=\"version\" description=\"Quartz version.\" type=\"java.lang.String\" writeable=\"false\"/>\n\t\t<attribute name=\"jobStoreClass\" description=\"Class of this scheduler's JobStore.\" type=\"java.lang.Class\" writeable=\"false\"/>\n\t\t<attribute name=\"threadPoolClass\" description=\"Class of this scheduler's ThreadPool.\" type=\"java.lang.Class\" writeable=\"false\"/>\n\t\t<attribute name=\"threadPoolSize\" description=\"Number of threads in this scheduler's ThreadPool.\" type=\"int\" writeable=\"false\"/>\n\t\t\n\t\t<!-- OPERATIONS-->\n\t\t<operation name=\"start\" description=\"Starts the scheduler's threads that fire Triggers.\" impact=\"ACTION\" returnType=\"void\"/>\n\t\t<operation name=\"standby\" description=\"Temporarily halts the scheduler's firing of Triggers.\" impact=\"ACTION\" returnType=\"void\"/>\n\t\t<operation name=\"shutdown\" description=\"Halts the scheduler's firing of Triggers, and cleans up all resources associated with the scheduler.\" impact=\"ACTION\" returnType=\"void\"/>\n\t\t<operation name=\"shutdown\" description=\"Halts the scheduler's firing of Triggers, and cleans up all resources associated with the scheduler.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"waitForJobsToComplete\" description=\"If true the scheduler will not allow this method to return until all currently executing jobs have completed.\" type=\"boolean\"/>\n\t\t</operation>\n\n\t\t<operation name=\"runningSince\" description=\"Get Date scheduler was first started.\" impact=\"INFO\" returnType=\"java.util.Date\"/>\n\t\t<operation name=\"numJobsExecuted\" description=\"Get total number of jobs executed by this scheduler.\" impact=\"INFO\" returnType=\"int\"/>\n\t\t<operation name=\"supportsPersistence\" description=\"Get whether this scheduler's JobStore supports persistence.\" impact=\"INFO\" returnType=\"boolean\"/>\n\t\t<operation name=\"getCurrentlyExecutingJobs\" description=\"Get a list of JobExecutionContext objects that represent all currently executing Jobs in this scheduler instance.\" impact=\"INFO\" returnType=\"java.util.List\"/>\n\n\t\t<operation name=\"scheduleJob\" description=\"Add the given JobDetail to the Scheduler, and associate the given Trigger with it.\" impact=\"ACTION\" returnType=\"java.util.Date\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobDetail\" type=\"org.quartz.JobDetail\" description=\"The JobDetail to schedule.\"/>\n\t\t\t<parameter name=\"trigger\" type=\"org.quartz.Trigger\" description=\"The Trigger to schedule.\"/>\n\t\t</operation>\n\t\t<operation name=\"scheduleJob\" description=\"Schedule the given Trigger with the Job identified by the Trigger's settings.\" impact=\"ACTION\" returnType=\"java.util.Date\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"trigger\" type=\"org.quartz.Trigger\" description=\"The Trigger to schedule.\"/>\n\t\t</operation>\n\t\t<operation name=\"unscheduleJob\" description=\"Remove the indicated Trigger from the scheduler.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the Trigger to unschedule.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Trigger to unschedule.\"/>\n\t\t</operation>\n\t\t<operation name=\"rescheduleJob\" description=\"Remove (delete) the Trigger with the given name, and store the new given one - which must be associated with the same job (the new trigger must have the job name and group specified) - however, the new trigger need not have the same name as the old trigger.\" impact=\"ACTION\" returnType=\"java.util.Date\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the Trigger to be replaced.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Trigger to be replaced.\"/>\n\t\t\t<parameter name=\"newTrigger\" type=\"org.quartz.Trigger\" description=\"The new Trigger to be stored.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"addJob\" description=\"Add the given Job to the Scheduler - with no associated Trigger.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobDetail\" type=\"org.quartz.JobDetail\" description=\"The JobDetail to add.\"/>\n\t\t\t<parameter name=\"replace\" type=\"boolean\" description=\"Whether or not to replace an existing Job with the given one.\"/>\n\t\t</operation>\n\t\t<operation name=\"deleteJob\" description=\"Delete the identified Job from the Scheduler - and any associated Triggers.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the Job to delete.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Job to delete.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"triggerJob\" description=\"Trigger the identified JobDetail (execute it now) - the generated trigger will be non-volatile.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the Job to trigger.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Job to trigger.\"/>\n\t\t\t<parameter name=\"jobDataMap\" type=\"org.quartz.JobDataMap\" description=\"The (possibly null) JobDataMap to be associated with the trigger that fires the job immediately.\"/>\n\t\t</operation>\n\t\t<operation name=\"triggerJobWithVolatileTrigger\" description=\"Trigger the identified JobDetail (execute it now) - the generated trigger will be volatile.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the Job to trigger.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Job to trigger.\"/>\n\t\t\t<parameter name=\"jobDataMap\" type=\"org.quartz.JobDataMap\" description=\"The (possibly null) JobDataMap to be associated with the trigger that fires the job immediately.\"/>\n\t\t</operation>\n\t\t\n\t\t\n\t\t<operation name=\"interrupt\" description=\"Request the interruption, within this scheduler instance, of all currently executing instances of the identified Job, which  must be an implementor of the InterruptableJob interface.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the trigger to interrupt.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The name of the trigger group to interrupt.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"pauseJob\" description=\"Pause the JobDetail with the given name - by pausing all of its current Triggers.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the Job to pause.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Job to pause.\"/>\n\t\t</operation>\n\t\t<operation name=\"pauseJobGroup\" description=\"Pause all of the JobDetails in the given group - by pausing all of theirTriggers.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Jobs to pause.\"/>\n\t\t</operation>\n\t\t<operation name=\"pauseTrigger\" description=\"Pause the Trigger with the given name.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the Trigger to pause.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Trigger to pause.\"/>\n\t\t</operation>\n\t\t<operation name=\"pauseTriggerGroup\" description=\"Pause all of the Triggers in the given group.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Triggers to pause.\"/>\n\t\t</operation>\t\t\n\t\t<operation name=\"resumeJob\" description=\"Resume (un-pause) the JobDetail with the given name.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the Job to resume.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Job to resume.\"/>\n\t\t</operation>\n\t\t<operation name=\"resumeJobGroup\" description=\"Resume (un-pause) all of the JobDetails in the given group.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The group name of the Jobs to resume.\"/>\n\t\t</operation>\n\t\t<operation name=\"resumeTrigger\" description=\"Resume (un-pause) the Trigger with the given name.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the Trigger to resume.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Trigger to resume.\"/>\n\t\t</operation>\n\t\t<operation name=\"resumeTriggerGroup\" description=\"Resume (un-pause) all of the Triggers in the given group.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The group name of the Triggers to resume.\"/>\n\t\t</operation>\n\t\t<operation name=\"pauseAll\" description=\"Pause all triggers - similar to calling pauseTriggerGroup(group) on every group, however, after using this method resumeAll() must be called to clear the scheduler's state of 'remembering' that all new triggers will be paused as they are added.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\t\t<operation name=\"resumeAll\" description=\"Resume (un-pause) all triggers - similar to calling resumeTriggerGroup(group) on every group.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\t\t<operation name=\"getPausedTriggerGroups\" description=\"Get the names of all Trigger groups that are paused.\" impact=\"INFO\" returnType=\"java.util.Set\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"getJobGroupNames\" description=\"Get the names of all known JobDetail groups.\" impact=\"INFO\" returnType=\"[Ljava.lang.String;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\t\t<operation name=\"getJobNames\" description=\"Get the names of all the JobDetails in the given group.\" impact=\"INFO\" returnType=\"[Ljava.lang.String;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The job group name.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTriggersOfJob\" description=\"Get all Triggers that are associated with the identified JobDetail.\" impact=\"INFO\" returnType=\"[Lorg.quartz.Trigger;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the job.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The name of the job group.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTriggerGroupNames\" description=\"Get the names of all known Trigger groups.\" impact=\"INFO\" returnType=\"[Ljava.lang.String;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTriggerNames\" description=\"Get the names of all the Triggers in the given group.\" impact=\"INFO\" returnType=\"[Ljava.lang.String;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The trigger group name.\"/>\n\t\t</operation>\n\t\t<operation name=\"getJobDetail\" description=\"Get the JobDetail for the Job instance with the given name and group.\" impact=\"INFO\" returnType=\"[Lorg.quartz.JobDetail;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"jobName\" type=\"java.lang.String\" description=\"The name of the job.\"/>\n\t\t\t<parameter name=\"jobGroupName\" type=\"java.lang.String\" description=\"The name of the job group.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTrigger\" description=\"Get the Trigger instance with the given name and group.\" impact=\"INFO\" returnType=\"[Lorg.quartz.Trigger;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the trigger.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The name of the trigger group.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTriggerState\" description=\"Get the current state of the identified Trigger.\" impact=\"INFO\" returnType=\"int\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"triggerName\" type=\"java.lang.String\" description=\"The name of the trigger.\"/>\n\t\t\t<parameter name=\"triggerGroupName\" type=\"java.lang.String\" description=\"The name of the trigger group.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"addCalendar\" description=\"Add (register) the given Calendar to the scheduler.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"calendarName\" type=\"java.lang.String\" description=\"Name of the calendar to add.\"/>\n\t\t\t<parameter name=\"calendar\" type=\"org.quartz.Calendar\" description=\"The Calendar instance to add.\"/>\n\t\t\t<parameter name=\"replace\" type=\"boolean\" description=\"Whether to allow replacing an existing Calendar instance.\"/>\n\t\t\t<parameter name=\"updateTriggers\" type=\"boolean\" description=\"Whether or not to update existing triggers that referenced the already existing calendar so that they are 'correct' based on the new trigger.\"/>\n\t\t</operation>\n\t\t<operation name=\"deleteCalendar\" description=\"Delete the identified Calendar from the scheduler.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"calendarName\" type=\"java.lang.String\" description=\"Name of the Calendar to delete.\"/>\n\t\t</operation>\n\t\t<operation name=\"getCalendar\" description=\"Get the Calendar instance with the given name.\" impact=\"INFO\" returnType=\"org.quartz.Calendar\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t\t<parameter name=\"calendarName\" type=\"java.lang.String\" description=\"Name of the Calendar to get.\"/>\n\t\t</operation>\n\t\t<operation name=\"getCalendarNames\" description=\"Get the names of all registered Calendars.\" impact=\"INFO\" returnType=\"[Ljava.lang.String;\">\n\t\t\t<parameter name=\"schedulingContext\" type=\"org.quartz.core.SchedulingContext\" description=\"The scheduling context.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"addGlobalJobListener\" description=\"Add the given JobListener to the scheduler's global list.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"jobListener\" type=\"org.quartz.JobListener\" description=\"Job listener to add.\"/>\n\t\t</operation>\n\t\t<operation name=\"addJobListener\" description=\"Add the given JobListener to the scheduler's list, of registered JobListeners.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"jobListener\" type=\"org.quartz.JobListener\" description=\"Job listener to add.\"/>\n\t\t</operation>\n\t\t<operation name=\"removeGlobalJobListener\" description=\"Remove the identified JobListener from the scheduler's list of global listeners.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"jobListenerName\" type=\"java.lang.String\" description=\"Name of the global JobListener to remove.\"/>\n\t\t</operation>\n\t\t<operation name=\"removeJobListener\" description=\"Remove the identified JobListener from the scheduler's list of registered listeners.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"jobListenerName\" type=\"java.lang.String\" description=\"Name of the JobListener to remove.\"/>\n\t\t</operation>\n\t\t<operation name=\"getGlobalJobListeners\" description=\"Get a List containing all of the JobListeners in the scheduler's global list.\" impact=\"INFO\" returnType=\"java.util.List\"/>\n\t\t<operation name=\"getJobListenerNames\" description=\"Get a Set containing the names of all the non-global JobListeners registered with the scheduler.\" impact=\"INFO\" returnType=\"java.util.Set\"/>\n\t\t<operation name=\"getGlobalJobListener\" description=\"Get the global JobListener that has the given name.\" impact=\"INFO\" returnType=\"org.quartz.JobListener\">\n\t\t\t<parameter name=\"jobListenerName\" type=\"java.lang.String\" description=\"Name of the global JobListener to get.\"/>\n\t\t</operation>\n\t\t<operation name=\"getJobListener\" description=\"Get the non-global JobListener that has the given name.\" impact=\"INFO\" returnType=\"org.quartz.JobListener\">\n\t\t\t<parameter name=\"jobListenerName\" type=\"java.lang.String\" description=\"Name of the JobListener to get.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"addGlobalTriggerListener\" description=\"Add the given TriggerListener to the scheduler's global list.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"triggerListener\" type=\"org.quartz.TriggerListener\" description=\"Trigger listener to add.\"/>\n\t\t</operation>\n\t\t<operation name=\"addTriggerListener\" description=\"Add the given TriggerListener to the scheduler's list, of registered TriggerListeners.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"triggerListener\" type=\"org.quartz.TriggerListener\" description=\"Trigger listener to add.\"/>\n\t\t</operation>\n\t\t<operation name=\"removeGlobalTriggerListener\" description=\"Remove the identified TriggerListener from the scheduler's list of global listeners.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"triggerListenerName\" type=\"java.lang.String\" description=\"Name of the global TriggerListener to remove.\"/>\n\t\t</operation>\n\t\t<operation name=\"removeTriggerListener\" description=\"Remove the identified TriggerListener from the scheduler's list of registered listeners.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"triggerListenerName\" type=\"java.lang.String\" description=\"Name of the TriggerListener to remove.\"/>\n\t\t</operation>\n\t\t<operation name=\"getGlobalTriggerListeners\" description=\"Get a List containing all of the TriggerListeners in the scheduler's global list.\" impact=\"INFO\" returnType=\"java.util.List\"/>\n\t\t<operation name=\"getTriggerListenerNames\" description=\"Get a Set containing the names of all the non-global TriggerListeners registered with the scheduler.\" impact=\"INFO\" returnType=\"java.util.Set\"/>\n\t\t<operation name=\"getGlobalTriggerListener\" description=\"Get the global TriggerListener that has the given name.\" impact=\"INFO\" returnType=\"org.quartz.TriggerListener\">\n\t\t\t<parameter name=\"triggerListenerName\" type=\"java.lang.String\" description=\"Name of the global TriggerListener to get.\"/>\n\t\t</operation>\n\t\t<operation name=\"getTriggerListener\" description=\"Get the non-global TriggerListener that has the given name.\" impact=\"INFO\" returnType=\"org.quartz.TriggerListener\">\n\t\t\t<parameter name=\"triggerListenerName\" type=\"java.lang.String\" description=\"Name of the TriggerListener to get.\"/>\n\t\t</operation>\n\n\t\t<operation name=\"addSchedulerListener\" description=\"Register the given SchedulerListener with the scheduler.\" impact=\"ACTION\" returnType=\"void\">\n\t\t\t<parameter name=\"schedulerListener\" type=\"org.quartz.SchedulerListener\" description=\"Scheduler listener to add.\"/>\n\t\t</operation>\n\t\t<operation name=\"removeSchedulerListener\" description=\"Remove the given SchedulerListener from the scheduler.\" impact=\"ACTION\" returnType=\"boolean\">\n\t\t\t<parameter name=\"schedulerListener\" type=\"org.quartz.SchedulerListener\" description=\"Scheduler listener to remove.\"/>\n\t\t</operation>\n\t\t<operation name=\"getSchedulerListeners\" description=\"Get a List containing all of the SchedulerListeners registered with the scheduler.\" impact=\"INFO\" returnType=\"java.util.List\"/>\n\t</mbean>\n</mbeans-descriptors>\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/core/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.core</title>\n</head>\n<body>\n<p>Contains the core classes and interfaces for the <b>Quartz</b> job scheduler.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project\n  for more information.\n\n</body>\n</html>"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jboss/doc-files/quartz-service.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<server>\n\n  <mbean code=\"org.quartz.ee.jmx.jboss.QuartzService\"\n      name=\"user:service=QuartzService,name=QuartzService\">\n\n    <!--\n        Wait until the DataSources  deployed. This option\n\tensures correct  deployment order at JBoss startup.\n\tChange the 'QuartzDS' to your datasource name.\n\tImportant!==> this is NOT the JNDI name of the datasource.\n\t(JNDI name for it is set in a separate xxx-service.xml file). \n     -->\n    <!-- <depends>jboss.jca:service=LocalTxCM,name=QuartzDS</depends> -->\n    <depends>jboss.jca:service=DataSourceBinding,name=QuartzDS</depends> \n    <!--\n        Wait for the deployment of XA-DataSource (if u have one ;)\n        The same as above, but for XA-compliant datasource.\n\tUncomment if you need it.\n    -->\n    <!--\n    <depends>jboss.jca:service=DataSourceBinding,name=QuartzDS-XA</depends> \n    -->\n    <!--\n    <depends>jboss.jca:service=XATxCM,name=QuartzDS-XA</depends>\n    -->\n\n    <!--\n      JNDI name for locating Scheduler, \"Quartz\" is default.\n    -->\n    <!--\n    <attribute name=\"JndiName\">Quartz</attribute>\n    -->\n\n    <!--\n       Call Scheduler.start() only if requested. Most of the time this \n       should be true. In some special cases you may want to have \n       scheduler service available but not run the jobs (for example, \n       if you want to administer the jobs on a particular server, only).\n       Default value is true.\n    -->\n    <!--\n     <attribute name=\"StartScheduler\">true</attribute>\n    -->\n\n    <!--\n      By default a Properties file named \"quartz.properties\" is\n      loaded from the 'current working directory'. If that fails,\n      then the \"quartz.properties\" file located (as a resource)\n      in the org/quartz package is loaded. If you wish to use a\n      file other than these defaults, you must either define the\n      system property 'org.quartz.properties' to point to the\n      file you want or set the PropertiesFile attribute. You\n      may also specify the properties directly by setting the\n      Properties attribute. You must use only one of these\n      methods to specify the properties.\n    -->\n\n    <!--\n      Initialize the SchedulerFactory with the contents\n      of the Properties file with the given name.\n    -->\n    <!--\n    <attribute name=\"PropertiesFile\">quartz.properties</attribute>\n    -->\n\n    <!--\n      Initialized the SchedulerFactory with the contents\n      of the given Properties object.\n    -->\n    \n    <attribute name=\"Properties\">\n      # Default Properties file for use by StdSchedulerFactory\n      # to create a Quartz Scheduler Instance, if a different\n      # properties file is not explicitly specified.\n      #\n\n      # org.quartz.scheduler.classLoadHelper.class = \n   \n      org.quartz.scheduler.instanceName = DefaultQuartzScheduler\n      org.quartz.scheduler.rmi.export = false\n      org.quartz.scheduler.rmi.proxy = false\n      org.quartz.scheduler.xaTransacted = false\n\n      org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool\n      org.quartz.threadPool.threadCount = 5\n      org.quartz.threadPool.threadPriority = 4\n\n      org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT\n      org.quartz.jobStore.driverDelegateClass =  org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n      org.quartz.jobStore.dataSource = QUARTZ\n      org.quartz.jobStore.nonManagedTXDataSource = QUARTZ_NO_TX\n      org.quartz.jobStore.tablePrefix = QRTZ_\n      org.quartz.dataSource.QUARTZ.jndiURL = java:/jdbc/QuartzDS\n      org.quartz.dataSource.QUARTZ_NO_TX.jndiURL = java:/jdbc/QuartzNoTxDS\n     \n      \n    </attribute>\n    \n\n  </mbean>\n\n</server>\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jmx/jboss/JBoss4RMIRemoteMBeanScheduler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.ee.jmx.jboss;\n\nimport org.quartz.SchedulerException;\nimport org.quartz.impl.RemoteMBeanScheduler;\n\nimport javax.management.AttributeList;\nimport javax.management.MBeanServerConnection;\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport java.util.Arrays;\nimport java.util.Properties;\n\n/**\n * <p>\n * An implementation of the <code>Scheduler</code> interface that remotely\n * proxies all method calls to the equivalent call on a given <code>QuartzScheduler</code>\n * instance, via JBoss's JMX RMIAdaptor.\n * </p>\n * \n * <p>\n * Set the <b>providerURL</b> property to your MBean server URL. \n * This defaults to: <i>jnp://localhost:1099</i>\n * </p>\n * \n * @see org.quartz.Scheduler\n * @see org.quartz.core.QuartzScheduler\n */\npublic class JBoss4RMIRemoteMBeanScheduler extends RemoteMBeanScheduler {\n\n    private static final String DEFAULT_PROVIDER_URL = \"jnp://localhost:1099\";\n    private static final String RMI_ADAPTOR_JNDI_NAME = \"jmx/rmi/RMIAdaptor\";\n    \n    private MBeanServerConnection server = null;\n    private String providerURL = DEFAULT_PROVIDER_URL;\n    \n    public JBoss4RMIRemoteMBeanScheduler() throws SchedulerException {\n    }\n    \n\n    /**\n     * Set the remote MBean server URL.  \n     * \n     * Defaults to: <i>jnp://localhost:1099</i>\n     */\n    public void setProviderURL(String providerURL) {\n        this.providerURL = providerURL;\n    }\n\n    /**\n     * Initialize this remote MBean scheduler, getting the JBoss\n     * RMIAdaptor for communication.\n     */\n    @Override\n    public void initialize() throws SchedulerException {\n        InitialContext ctx = null;\n        try {\n            ctx = new InitialContext(getContextProperties());\n            server = (MBeanServerConnection)ctx.lookup(RMI_ADAPTOR_JNDI_NAME);\n        } catch (Exception e) {\n            throw new SchedulerException(\"Failed to lookup JBoss JMX RMI Adaptor.\", e);\n        } finally {\n            if (ctx != null) {\n                try {\n                    ctx.close();\n                } catch (NamingException ignore) {\n                }\n            }\n        }\n    }\n    \n    /**\n     * Get the properties to use when creating a JNDI InitialContext.\n     * \n     * <p>\n     * This method is broken out so it can be extended to pass credentials\n     * or other properties not currently supported. \n     * </p>\n     */\n    protected Properties getContextProperties() {\n        Properties props = new Properties();\n        props.put(Context.INITIAL_CONTEXT_FACTORY, \"org.jnp.interfaces.NamingContextFactory\");\n        props.put(Context.URL_PKG_PREFIXES, \"org.jboss.naming:org.jnp.interfaces\");\n        props.put(Context.PROVIDER_URL, providerURL);\n        \n        return props;\n    }\n\n    @Override\n    protected Object getAttribute(String attribute) throws SchedulerException {\n        try {\n            return server.getAttribute(getSchedulerObjectName(), attribute);\n        } catch (Exception e) {\n            throw new SchedulerException(\"Failed to get Scheduler MBean attribute: \" + attribute, e);\n        }\n    }\n\n    @Override\n    protected AttributeList getAttributes(String[] attributes) throws SchedulerException {\n        try {\n            return server.getAttributes(getSchedulerObjectName(), attributes);\n        } catch (Exception e) {\n            throw new SchedulerException(\"Failed to get Scheduler MBean attributes: \" + Arrays.asList(attributes), e);\n        }\n    }\n\n    @Override\n    protected Object invoke(String operationName, Object[] params,\n            String[] signature) throws SchedulerException {\n        try {\n            return server.invoke(getSchedulerObjectName(), operationName, params, signature);\n        } catch (Exception e) {\n            throw new SchedulerException(\n                \"Failed to invoke Scheduler MBean operation: \" + operationName, e);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jmx/jboss/QuartzService.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jmx.jboss;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Properties;\n\nimport javax.naming.InitialContext;\nimport javax.naming.Name;\nimport javax.naming.NamingException;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.impl.StdSchedulerFactory;\n\nimport org.jboss.naming.NonSerializableFactory;\nimport org.jboss.system.ServiceMBeanSupport;\n\n/**\n * JBoss specific MBean implementation for configuring, starting, and\n * binding to JNDI a Quartz Scheduler instance.\n *  \n * <p> \n * Sample MBean deployment descriptor: \n * <a href=\"doc-files/quartz-service.xml\">quartz-service.xml</a>\n * </p>\n * \n * <p> \n * <b>Note:</b> The Scheduler instance bound to JNDI is not Serializable, so \n * you will get a null reference back if you try to retrieve it from outside\n * the JBoss server in which it was bound.  If you have a need for remote \n * access to a Scheduler instance you may want to consider using Quartz's RMI \n * support instead.  \n * </p>\n * \n * @see org.quartz.ee.jmx.jboss.QuartzServiceMBean\n * \n * @author Andrew Collins\n */\npublic class QuartzService extends ServiceMBeanSupport implements\n        QuartzServiceMBean {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Properties properties;\n\n    private StdSchedulerFactory schedulerFactory;\n\n    private String jndiName;\n\n    private String propertiesFile;\n\n    private boolean error;\n\n    private boolean useProperties;\n\n    private boolean usePropertiesFile;\n\n    /*\n    * If true, the scheduler will be started. If false, the scheduler is initialized \n    * (and available) but start() is not called - it will not execute jobs. \n    */\n    private boolean startScheduler = true;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public QuartzService() {\n        // flag initialization errors\n        error = false;\n\n        // use PropertiesFile attribute\n        usePropertiesFile = false;\n        propertiesFile = \"\";\n\n        // use Properties attribute\n        useProperties = false;\n        properties = new Properties();\n\n        // default JNDI name for Scheduler\n        jndiName = \"Quartz\";\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void setJndiName(String jndiName) throws Exception {\n        String oldName = this.jndiName;\n        this.jndiName = jndiName;\n\n        if (super.getState() == STARTED) {\n            unbind(oldName);\n\n            try {\n                rebind();\n            } catch (NamingException ne) {\n                log.error(\"Failed to rebind Scheduler\", ne);\n\n                throw new SchedulerConfigException(\n                        \"Failed to rebind Scheduler - \", ne);\n            }\n        }\n    }\n\n    public String getJndiName() {\n        return jndiName;\n    }\n\n    @Override\n    public String getName() {\n        return \"QuartzService(\" + jndiName + \")\";\n    }\n\n    public void setProperties(String properties) {\n        if (usePropertiesFile) {\n            log\n                    .error(\"Must specify only one of 'Properties' or 'PropertiesFile'\");\n\n            error = true;\n\n            return;\n        }\n\n        useProperties = true;\n\n        try {\n            properties = properties.replace(File.separator, \"/\");\n            ByteArrayInputStream bais = new ByteArrayInputStream(properties\n                    .getBytes());\n            this.properties = new Properties();\n            this.properties.load(bais);\n        } catch (IOException ioe) {\n            // should not happen\n        }\n    }\n\n    public String getProperties() {\n        try {\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            properties.store(baos, \"\");\n\n            return new String(baos.toByteArray());\n        } catch (IOException ioe) {\n            // should not happen\n            return \"\";\n        }\n    }\n\n    public void setPropertiesFile(String propertiesFile) {\n        if (useProperties) {\n            log\n                    .error(\"Must specify only one of 'Properties' or 'PropertiesFile'\");\n\n            error = true;\n\n            return;\n        }\n\n        usePropertiesFile = true;\n\n        this.propertiesFile = propertiesFile;\n    }\n\n    public String getPropertiesFile() {\n        return propertiesFile;\n    }\n\n    public void setStartScheduler(boolean startScheduler) {\n        this.startScheduler = startScheduler;\n    }\n    \n    public boolean getStartScheduler() {\n        return startScheduler;\n    }    \n    \n    @Override\n    public void createService() throws Exception {\n        log.info(\"Create QuartzService(\" + jndiName + \")...\");\n\n        if (error) {\n            log\n                    .error(\"Must specify only one of 'Properties' or 'PropertiesFile'\");\n\n            throw new Exception(\n                    \"Must specify only one of 'Properties' or 'PropertiesFile'\");\n        }\n\n        schedulerFactory = new StdSchedulerFactory();\n\n        try {\n            if (useProperties) {\n                schedulerFactory.initialize(properties);\n            }\n\n            if (usePropertiesFile) {\n                schedulerFactory.initialize(propertiesFile);\n            }\n        } catch (Exception e) {\n            log.error(\"Failed to initialize Scheduler\", e);\n\n            throw new SchedulerConfigException(\n                    \"Failed to initialize Scheduler - \", e);\n        }\n\n        log.info(\"QuartzService(\" + jndiName + \") created.\");\n    }\n\n    @Override\n    public void destroyService() throws Exception {\n        log.info(\"Destroy QuartzService(\" + jndiName + \")...\");\n\n        schedulerFactory = null;\n\n        log.info(\"QuartzService(\" + jndiName + \") destroyed.\");\n    }\n\n    @Override\n    public void startService() throws Exception {\n        log.info(\"Start QuartzService(\" + jndiName + \")...\");\n\n        try {\n            rebind();\n        } catch (NamingException ne) {\n            log.error(\"Failed to rebind Scheduler\", ne);\n\n            throw new SchedulerConfigException(\"Failed to rebind Scheduler - \",\n                    ne);\n        }\n\n        try {\n            Scheduler scheduler = schedulerFactory.getScheduler();\n\n            if (startScheduler) {\n                scheduler.start();\n            } else {\n                log.info(\"Skipping starting the scheduler (will not run jobs).\");\n            }\n        } catch (Exception e) {\n            log.error(\"Failed to start Scheduler\", e);\n\n            throw new SchedulerConfigException(\"Failed to start Scheduler - \",\n                    e);\n        }\n\n        log.info(\"QuartzService(\" + jndiName + \") started.\");\n    }\n\n    @Override\n    public void stopService() throws Exception {\n        log.info(\"Stop QuartzService(\" + jndiName + \")...\");\n\n        try {\n            Scheduler scheduler = schedulerFactory.getScheduler();\n\n            scheduler.shutdown();\n        } catch (Exception e) {\n            log.error(\"Failed to shutdown Scheduler\", e);\n\n            throw new SchedulerConfigException(\n                    \"Failed to shutdown Scheduler - \", e);\n        }\n\n        unbind(jndiName);\n\n        log.info(\"QuartzService(\" + jndiName + \") stopped.\");\n    }\n\n    private void rebind() throws NamingException, SchedulerException {\n        InitialContext rootCtx = null;\n        try {\n            rootCtx = new InitialContext();\n            Name fullName = rootCtx.getNameParser(\"\").parse(jndiName);\n            Scheduler scheduler = schedulerFactory.getScheduler();\n            NonSerializableFactory.rebind(fullName, scheduler, true);\n        } finally {\n            if (rootCtx != null) { \n                try { \n                    rootCtx.close(); \n                } catch (NamingException ignore) {} \n            }\n        }\n    }\n    \n    private void unbind(String name) {\n        InitialContext rootCtx = null;\n        try {\n            rootCtx = new InitialContext();\n            rootCtx.unbind(name);\n            NonSerializableFactory.unbind(name);\n        } catch (NamingException e) {\n            log.warn(\"Failed to unbind scheduler with jndiName: \" + name, e); \n        } finally {\n            if (rootCtx != null) { \n                try { \n                    rootCtx.close(); \n                } catch (NamingException ignore) {} \n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jmx/jboss/QuartzServiceMBean.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jmx.jboss;\n\nimport org.jboss.system.ServiceMBean;\n\n/**\n * Interface exposed via JMX for MBean for configuring, starting, and\n * binding to JNDI a Quartz Scheduler instance.\n *  \n * <p> \n * Sample MBean deployment descriptor: \n * <a href=\"doc-files/quartz-service.xml\">quartz-service.xml</a>\n * </p>\n * \n * <p> \n * <b>Note:</b> The Scheduler instance bound to JNDI is not Serializable, so \n * you will get a null reference back if you try to retrieve it from outside\n * the JBoss server in which it was bound.  If you have a need for remote \n * access to a Scheduler instance you may want to consider using Quartz's RMI \n * support instead.  \n * </p>\n * \n * @see org.quartz.ee.jmx.jboss.QuartzService\n * \n * @author Andrew Collins\n */\npublic interface QuartzServiceMBean extends ServiceMBean {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    void setJndiName(String jndiName) throws Exception;\n\n    String getJndiName();\n\n    void setProperties(String properties);\n\n    void setPropertiesFile(String propertiesFile);\n    \n    void setStartScheduler(boolean startScheduler);    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jta/JTAAnnotationAwareJobRunShellFactory.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jta;\n\nimport org.quartz.ExecuteInJTATransaction;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.core.JobRunShell;\nimport org.quartz.core.JobRunShellFactory;\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.quartz.utils.ClassUtils;\n\n/**\n * <p>\n * Responsible for creating the instances of a {@link JobRunShell}\n * to be used within the <code>{@link org.quartz.core.QuartzScheduler}</code>\n * instance.  It will create a standard {@link JobRunShell}\n * unless the job class has the {@link ExecuteInJTATransaction}\n * annotation in which case it will create a {@link JTAJobRunShell}.\n * </p>\n * \n * <p>\n * This implementation does not re-use any objects, it simply makes a new\n * JTAJobRunShell each time <code>borrowJobRunShell()</code> is called.\n * </p>\n * \n * @author James House\n */\npublic class JTAAnnotationAwareJobRunShellFactory implements JobRunShellFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Scheduler scheduler;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public JTAAnnotationAwareJobRunShellFactory() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Initialize the factory, providing a handle to the <code>Scheduler</code>\n     * that should be made available within the <code>JobRunShell</code> and\n     * the <code>JobExecutionContext</code> s within it, and a handle to the\n     * <code>SchedulingContext</code> that the shell will use in its own\n     * operations with the <code>JobStore</code>.\n     * </p>\n     */\n    public void initialize(Scheduler sched)\n        throws SchedulerConfigException {\n        this.scheduler = sched;\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>\n     * to obtain instances of <code>{@link org.quartz.core.JobRunShell}</code>.\n     * </p>\n     */\n    public JobRunShell createJobRunShell(TriggerFiredBundle bundle)\n            throws SchedulerException {\n        ExecuteInJTATransaction jtaAnnotation = ClassUtils.getAnnotation(bundle.getJobDetail().getJobClass(), ExecuteInJTATransaction.class);\n        if(jtaAnnotation == null)\n            return new JobRunShell(scheduler, bundle);\n        else {\n            int timeout = jtaAnnotation.timeout();\n            if (timeout >= 0) {\n                return new JTAJobRunShell(scheduler, bundle, timeout);\n            } else {\n                return new JTAJobRunShell(scheduler, bundle);\n            }\n        }\n    }\n\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jta/JTAJobRunShell.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jta;\n\nimport jakarta.transaction.Status;\nimport jakarta.transaction.SystemException;\nimport jakarta.transaction.UserTransaction;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.core.JobRunShell;\nimport org.quartz.spi.TriggerFiredBundle;\n\n/**\n * <p>\n * An extension of <code>{@link org.quartz.core.JobRunShell}</code> that\n * begins an XA transaction before executing the Job, and commits (or\n * rolls-back) the transaction after execution completes.\n * </p>\n * \n * @see org.quartz.core.JobRunShell\n * \n * @author James House\n */\npublic class JTAJobRunShell extends JobRunShell {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    private final Integer transactionTimeout;\n\n    private UserTransaction ut;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a JTAJobRunShell instance with the given settings.\n     * </p>\n     */\n    public JTAJobRunShell(Scheduler scheduler, TriggerFiredBundle bundle) {\n        super(scheduler, bundle);\n        this.transactionTimeout = null;\n    }\n\n    /**\n     * <p>\n     * Create a JTAJobRunShell instance with the given settings.\n     * </p>\n     */\n    public JTAJobRunShell(Scheduler scheduler, TriggerFiredBundle bundle, int timeout) {\n        super(scheduler, bundle);\n        this.transactionTimeout = timeout;\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    @Override\n    protected void begin() throws SchedulerException {\n        // Don't get a new UserTransaction w/o making sure we cleaned up the old \n        // one.  This is necessary because there are paths through JobRunShell.run()\n        // where begin() can be called multiple times w/o complete being called in\n        // between.\n        cleanupUserTransaction();\n        \n        boolean beganSuccessfully = false;\n        try {\n            getLog().debug(\"Looking up UserTransaction.\");\n            ut = UserTransactionHelper.lookupUserTransaction();\n            if (transactionTimeout != null) {\n                ut.setTransactionTimeout(transactionTimeout);\n            }\n\n            getLog().debug(\"Beginning UserTransaction.\");\n            ut.begin();\n            \n            beganSuccessfully = true;\n        } catch (SchedulerException se) {\n            throw se;\n        } catch (Exception nse) {\n\n            throw new SchedulerException(\n                    \"JTAJobRunShell could not start UserTransaction.\", nse);\n        } finally {\n            if (!beganSuccessfully) {\n                cleanupUserTransaction();\n            }\n        }\n    }\n\n    @Override\n    protected void complete(boolean successfulExecution)\n        throws SchedulerException {\n        if (ut == null) {\n            return;\n        }\n\n        try {\n            try {\n                if (ut.getStatus() == Status.STATUS_MARKED_ROLLBACK) {\n                    getLog().debug(\"UserTransaction marked for rollback only.\");\n                    successfulExecution = false;\n                }\n            } catch (SystemException e) {\n                throw new SchedulerException(\n                        \"JTAJobRunShell could not read UserTransaction status.\", e);\n            }\n    \n            if (successfulExecution) {\n                try {\n                    getLog().debug(\"Committing UserTransaction.\");\n                    ut.commit();\n                } catch (Exception nse) {\n                    throw new SchedulerException(\n                            \"JTAJobRunShell could not commit UserTransaction.\", nse);\n                }\n            } else {\n                try {\n                    getLog().debug(\"Rolling-back UserTransaction.\");\n                    ut.rollback();\n                } catch (Exception nse) {\n                    throw new SchedulerException(\n                            \"JTAJobRunShell could not rollback UserTransaction.\",\n                            nse);\n                }\n            }\n        } finally {\n            cleanupUserTransaction();\n        }\n    }\n\n    /**\n     * Override passivate() to ensure we always cleanup the UserTransaction. \n     */\n    @Override\n    public void passivate() {\n        cleanupUserTransaction();\n        super.passivate();\n    }\n    \n    private void cleanupUserTransaction() {\n        if (ut != null) {\n            UserTransactionHelper.returnUserTransaction(ut);\n            ut = null;\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jta/JTAJobRunShellFactory.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jta;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.core.JobRunShell;\nimport org.quartz.core.JobRunShellFactory;\nimport org.quartz.spi.TriggerFiredBundle;\n\n/**\n * <p>\n * Responsible for creating the instances of <code>{@link org.quartz.ee.jta.JTAJobRunShell}</code>\n * to be used within the <code>{@link org.quartz.core.QuartzScheduler}</code> instance.\n * </p>\n * \n * <p>\n * This implementation does not re-use any objects, it simply makes a new\n * JTAJobRunShell each time <code>borrowJobRunShell()</code> is called.\n * </p>\n * \n * @author James House\n */\npublic class JTAJobRunShellFactory implements JobRunShellFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Scheduler scheduler;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public JTAJobRunShellFactory() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Initialize the factory, providing a handle to the <code>Scheduler</code>\n     * that should be made available within the <code>JobRunShell</code> and\n     * the <code>JobExecutionContext</code> s within it, and a handle to the\n     * <code>SchedulingContext</code> that the shell will use in its own\n     * operations with the <code>JobStore</code>.\n     * </p>\n     */\n    public void initialize(Scheduler sched)\n        throws SchedulerConfigException {\n        this.scheduler = sched;\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>\n     * to obtain instances of <code>{@link org.quartz.core.JobRunShell}</code>.\n     * </p>\n     */\n    public JobRunShell createJobRunShell(TriggerFiredBundle bundle)\n            throws SchedulerException {\n        return new JTAJobRunShell(scheduler, bundle);\n    }\n\n\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/jta/UserTransactionHelper.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.ee.jta;\n\nimport javax.naming.InitialContext;\nimport jakarta.transaction.HeuristicMixedException;\nimport jakarta.transaction.HeuristicRollbackException;\nimport jakarta.transaction.NotSupportedException;\nimport jakarta.transaction.RollbackException;\nimport jakarta.transaction.SystemException;\nimport jakarta.transaction.UserTransaction;\n\nimport org.quartz.SchedulerException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * A helper for obtaining a handle to a UserTransaction...\n * </p>\n * <p>\n * To ensure proper cleanup of the InitalContext used to create/lookup\n * the UserTransaction, be sure to always call returnUserTransaction() when\n * you are done with the UserTransaction. \n * </p>\n * \n * @author James House\n */\npublic class UserTransactionHelper {\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String DEFAULT_USER_TX_LOCATION = \"java:comp/UserTransaction\";\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private static String userTxURL = DEFAULT_USER_TX_LOCATION;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Do not allow the creation of an all static utility class.\n     */\n    private UserTransactionHelper() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static String getUserTxLocation() {\n        return userTxURL;\n    }\n\n    /**\n     * Set the JNDI URL at which the Application Server's UserTransaction can\n     * be found. If not set, the default value is \"java:comp/UserTransaction\" -\n     * which works for nearly all application servers.\n     */\n    public static void setUserTxLocation(String userTxURL) {\n        if (userTxURL != null) {\n            UserTransactionHelper.userTxURL = userTxURL;\n        }\n    }\n\n    /**\n     * Create/Lookup a UserTransaction in the InitialContext via the\n     * name set in setUserTxLocation().\n     */\n    public static UserTransaction lookupUserTransaction() throws SchedulerException {\n        return new UserTransactionWithContext();\n    }\n    \n    /**\n     * Return a UserTransaction that was retrieved via getUserTransaction().\n     * This will make sure that the InitalContext used to lookup/create the \n     * UserTransaction is properly cleaned up.\n     */\n    public static void returnUserTransaction(UserTransaction userTransaction) {\n        if ((userTransaction != null) && \n            (userTransaction instanceof UserTransactionWithContext)) {\n            UserTransactionWithContext userTransactionWithContext = \n                (UserTransactionWithContext)userTransaction;\n            \n            userTransactionWithContext.closeContext();\n        }\n    }\n\n\n    /**\n     * This class wraps a UserTransaction with the InitialContext that was used\n     * to look it up, so that when the UserTransaction is returned to the \n     * UserTransactionHelper the InitialContext can be closed.\n     */\n    private static class UserTransactionWithContext implements UserTransaction {\n        InitialContext context;\n        UserTransaction userTransaction;\n        \n        public UserTransactionWithContext() throws SchedulerException {\n            try {\n                context = new InitialContext();\n            } catch (Throwable t) {\n                throw new SchedulerException(\n                    \"UserTransactionHelper failed to create InitialContext to lookup/create UserTransaction.\", t);\n            }\n            \n            try {\n                userTransaction = (UserTransaction)context.lookup(userTxURL);\n            } catch (Throwable t) {\n                closeContext();\n                throw new SchedulerException(\n                    \"UserTransactionHelper could not lookup/create UserTransaction.\",\n                    t);\n            }\n            \n            if (userTransaction == null) {\n                closeContext();\n                throw new SchedulerException(\n                    \"UserTransactionHelper could not lookup/create UserTransaction from the InitialContext.\");\n            }\n        }\n\n        /**\n         * Close the InitialContext that was used to lookup/create the\n         * underlying UserTransaction.\n         */\n        public void closeContext() {\n            try {\n                if (context != null) {\n                    context.close();\n                }\n            } catch (Throwable t) {\n                getLog().warn(\"Failed to close InitialContext used to get a UserTransaction.\", t);\n            }\n            context = null;\n        }\n\n        /**\n         * When we are being garbage collected, make sure we were properly\n         * returned to the UserTransactionHelper.\n         */\n        @Override\n        protected void finalize() throws Throwable {\n            try {\n                if (context != null) {\n                    getLog().warn(\"UserTransaction was never returned to the UserTransactionHelper.\");\n                    closeContext();\n                }\n            } finally {\n                super.finalize();\n            }\n        }\n\n        private static Logger getLog() {\n            return LoggerFactory.getLogger(UserTransactionWithContext.class);\n        }\n        \n        // Wrapper methods that just delegate to the underlying UserTransaction\n        \n        public void begin() throws NotSupportedException, SystemException {\n            userTransaction.begin();\n        }\n\n        public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {\n            userTransaction.commit();        \n        }\n\n        public void rollback() throws IllegalStateException, SecurityException, SystemException {\n            userTransaction.rollback();\n        }\n\n        public void setRollbackOnly() throws IllegalStateException, SystemException {\n            userTransaction.setRollbackOnly();\n        }\n\n        public int getStatus() throws SystemException {\n            return userTransaction.getStatus();\n        }\n\n        public void setTransactionTimeout(int seconds) throws SystemException {\n            userTransaction.setTransactionTimeout(seconds);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/servlet/QuartzInitializerListener.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.ee.servlet;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.impl.StdSchedulerFactory;\n\n/**\n * <p>\n * A ServletContextListener that can be used to initialize Quartz.\n * </p>\n *\n * <p>\n * You'll want to add something like this to your WEB-INF/web.xml file:\n * </p>\n * <pre>\n *     &lt;context-param&gt;\n *         &lt;param-name&gt;quartz:config-file&lt;/param-name&gt;\n *         &lt;param-value&gt;/some/path/my_quartz.properties&lt;/param-value&gt;\n *     &lt;/context-param&gt;\n *     &lt;context-param&gt;\n *         &lt;param-name&gt;quartz:shutdown-on-unload&lt;/param-name&gt;\n *         &lt;param-value&gt;true&lt;/param-value&gt;\n *     &lt;/context-param&gt;\n *     &lt;context-param&gt;\n *         &lt;param-name&gt;quartz:wait-on-shutdown&lt;/param-name&gt;\n *         &lt;param-value&gt;true&lt;/param-value&gt;\n *     &lt;/context-param&gt;\n *     &lt;context-param&gt;\n *         &lt;param-name&gt;quartz:start-on-load&lt;/param-name&gt;\n *         &lt;param-value&gt;true&lt;/param-value&gt;\n *     &lt;/context-param&gt;\n *     \n *     &lt;listener&gt;\n *         &lt;listener-class&gt;\n *             org.quartz.ee.servlet.QuartzInitializerListener\n *         &lt;/listener-class&gt;\n *     &lt;/listener&gt;\n * </pre>\n * <p>\n * The init parameter 'quartz:config-file' can be used to specify the path (and\n * filename) of your Quartz properties file. If you leave out this parameter,\n * the default (\"quartz.properties\") will be used.\n * </p>\n *\n * <p>\n * The init parameter 'quartz:shutdown-on-unload' can be used to specify whether you\n * want scheduler.shutdown() called when the listener is unloaded (usually when\n * the application server is being shutdown). Possible values are \"true\" or\n * \"false\". The default is \"true\".\n * </p>\n *\n * <p>\n * The init parameter 'quartz:wait-on-shutdown' has effect when \n * 'quartz:shutdown-on-unload' is specified \"true\", and indicates whether you\n * want scheduler.shutdown(true) called when the listener is unloaded (usually when\n * the application server is being shutdown).  Passing \"true\" to the shutdown() call\n * causes the scheduler to wait for existing jobs to complete. Possible values are \n * \"true\" or \"false\". The default is \"false\".\n * </p>\n * \n * <p>\n * The init parameter 'quartz:start-on-load' can be used to specify whether\n * you want the scheduler.start() method called when the listener is first loaded.\n * If set to false, your application will need to call the start() method before\n * the scheduler begins to run and process jobs. Possible values are \"true\" or\n * \"false\". The default is \"true\", which means the scheduler is started.\n * </p>\n *\n * A StdSchedulerFactory instance is stored into the ServletContext. You can gain access\n * to the factory from a ServletContext instance like this:\n * <br>\n * <pre>\n * StdSchedulerFactory factory = (StdSchedulerFactory) ctx\n *                .getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);</pre>\n * <p>\n * The init parameter 'quartz:servlet-context-factory-key' can be used to override the\n * name under which the StdSchedulerFactory is stored into the ServletContext, in \n * which case you will want to use this name rather than \n * <code>QuartzInitializerListener.QUARTZ_FACTORY_KEY</code> in the above example.\n * </p>\n *\n * <p>\n * The init parameter 'quartz:scheduler-context-servlet-context-key' if set, the \n * ServletContext will be stored in the SchedulerContext under the given key\n * name (and will therefore be available to jobs during execution). \n * </p>\n *\n * <p>\n * The init parameter 'quartz:start-delay-seconds' can be used to specify the amount\n * of time to wait after initializing the scheduler before scheduler.start()\n * is called.\n * </p>\n *\n * Once you have the factory instance, you can retrieve the Scheduler instance by calling\n * <code>getScheduler()</code> on the factory.\n *\n * @author James House\n * @author Chuck Cavaness\n * @author John Petrocik\n */\npublic class QuartzInitializerListener implements ServletContextListener {\n\n    public static final String QUARTZ_FACTORY_KEY = \"org.quartz.impl.StdSchedulerFactory.KEY\";\n\n    private boolean performShutdown = true;\n    private boolean waitOnShutdown = false;\n\n    private Scheduler scheduler = null;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void contextInitialized(ServletContextEvent sce) {\n\n        log.info(\"Quartz Initializer Servlet loaded, initializing Scheduler...\");\n\n        ServletContext servletContext = sce.getServletContext();\n        StdSchedulerFactory factory;\n        try {\n\n            String configFile = servletContext.getInitParameter(\"quartz:config-file\");\n            if(configFile == null)\n                configFile = servletContext.getInitParameter(\"config-file\"); // older name, for backward compatibility\n            String shutdownPref = servletContext.getInitParameter(\"quartz:shutdown-on-unload\");\n            if(shutdownPref == null)\n                shutdownPref = servletContext.getInitParameter(\"shutdown-on-unload\");\n            if (shutdownPref != null) {\n                performShutdown = Boolean.parseBoolean(shutdownPref);\n            }\n            String shutdownWaitPref = servletContext.getInitParameter(\"quartz:wait-on-shutdown\");\n            if (shutdownWaitPref != null) {\n                waitOnShutdown = Boolean.parseBoolean(shutdownWaitPref);\n            }\n\n            factory = getSchedulerFactory(configFile);\n\n            // Always want to get the scheduler, even if it isn't starting, \n            // to make sure it is both initialized and registered.\n            scheduler = factory.getScheduler();\n\n            // Should the Scheduler being started now or later\n            String startOnLoad = servletContext.getInitParameter(\"quartz:start-on-load\");\n            if(startOnLoad == null)\n                startOnLoad = servletContext.getInitParameter(\"start-scheduler-on-load\");\n\n            int startDelay = 0;\n            String startDelayS = servletContext.getInitParameter(\"quartz:start-delay-seconds\");\n            if(startDelayS == null)\n                startDelayS = servletContext.getInitParameter(\"start-delay-seconds\");\n            try {\n                if(startDelayS != null && !startDelayS.trim().isEmpty())\n                    startDelay = Integer.parseInt(startDelayS);\n            } catch(Exception e) {\n                log.error(\"Cannot parse value of 'start-delay-seconds' to an integer: {}, defaulting to 5 seconds.\", startDelayS);\n                startDelay = 5;\n            }\n\n            /*\n             * If the \"quartz:start-on-load\" init-parameter is not specified,\n             * the scheduler will be started. This is to maintain backwards\n             * compatability.\n             */\n            if (startOnLoad == null || (Boolean.parseBoolean(startOnLoad))) {\n                if(startDelay <= 0) {\n                    // Start now\n                    scheduler.start();\n                    log.info(\"Scheduler has been started...\");\n                }\n                else {\n                    // Start delayed\n                    scheduler.startDelayed(startDelay);\n                    log.info(\"Scheduler will start in {} seconds.\", startDelay);\n                }\n            } else {\n                log.info(\"Scheduler has not been started. Use scheduler.start()\");\n            }\n\n            String factoryKey = servletContext.getInitParameter(\"quartz:servlet-context-factory-key\");\n            if(factoryKey == null)\n                factoryKey = servletContext.getInitParameter(\"servlet-context-factory-key\");\n            if (factoryKey == null) {\n                factoryKey = QUARTZ_FACTORY_KEY;\n            }\n\n            log.info(\"Storing the Quartz Scheduler Factory in the servlet context at key: {}\", factoryKey);\n            servletContext.setAttribute(factoryKey, factory);\n            \n            \n            String servletCtxKey = servletContext.getInitParameter(\"quartz:scheduler-context-servlet-context-key\");\n            if(servletCtxKey == null)\n                servletCtxKey = servletContext.getInitParameter(\"scheduler-context-servlet-context-key\");\n            if (servletCtxKey != null) {\n                log.info(\"Storing the ServletContext in the scheduler context at key: {}\", servletCtxKey);\n                scheduler.getContext().put(servletCtxKey, servletContext);\n            }\n\n        } catch (Exception e) {\n            log.error(\"Quartz Scheduler failed to initialize: {}\", String.valueOf(e));\n            e.printStackTrace();\n        }\n    }\n\n    protected StdSchedulerFactory getSchedulerFactory(String configFile)\n            throws SchedulerException {\n        StdSchedulerFactory factory;\n        // get Properties\n        if (configFile != null) {\n            factory = new StdSchedulerFactory(configFile);\n        } else {\n            factory = new StdSchedulerFactory();\n        }\n        return factory;\n    }\n\n    public void contextDestroyed(ServletContextEvent sce) {\n\n        if (!performShutdown) {\n            return;\n        }\n\n        try {\n            if (scheduler != null) {\n                scheduler.shutdown(waitOnShutdown);\n            }\n        } catch (Exception e) {\n            log.error(\"Quartz Scheduler failed to shutdown cleanly: {}\", String.valueOf(e));\n            e.printStackTrace();\n        }\n\n        log.info(\"Quartz Scheduler successful shutdown.\");\n    }\n\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/ee/servlet/QuartzInitializerServlet.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.ee.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.ServletConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.impl.StdSchedulerFactory;\n\n/**\n * <p>\n * A Servlet that can be used to initialize Quartz, if configured as a\n * load-on-startup servlet in a web application.\n * </p>\n *\n * <p>Using this start-up servlet may be preferred to using the {@link QuartzInitializerListener}\n * in some situations - namely when you want to initialize more than one scheduler in the same\n * application.</p>\n *\n * <p>\n * You'll want to add something like this to your WEB-INF/web.xml file:\n * </p>\n * <pre>\n *     &lt;servlet&gt;\n *         &lt;servlet-name&gt;\n *             QuartzInitializer\n *         &lt;/servlet-name&gt;\n *         &lt;display-name&gt;\n *             Quartz Initializer Servlet\n *         &lt;/display-name&gt;\n *         &lt;servlet-class&gt;\n *             org.quartz.ee.servlet.QuartzInitializerServlet\n *         &lt;/servlet-class&gt;\n *         &lt;load-on-startup&gt;\n *             1\n *         &lt;/load-on-startup&gt;\n *         &lt;init-param&gt;\n *             &lt;param-name&gt;config-file&lt;/param-name&gt;\n *             &lt;param-value&gt;/some/path/my_quartz.properties&lt;/param-value&gt;\n *         &lt;/init-param&gt;\n *         &lt;init-param&gt;\n *             &lt;param-name&gt;shutdown-on-unload&lt;/param-name&gt;\n *             &lt;param-value&gt;true&lt;/param-value&gt;\n *         &lt;/init-param&gt;\n *         &lt;init-param&gt;\n *             &lt;param-name&gt;wait-on-shutdown&lt;/param-name&gt;\n *             &lt;param-value&gt;true&lt;/param-value&gt;\n *         &lt;/init-param&gt;\n *         &lt;init-param&gt;\n *             &lt;param-name&gt;start-scheduler-on-load&lt;/param-name&gt;\n *             &lt;param-value&gt;true&lt;/param-value&gt;\n *         &lt;/init-param&gt;\n *     &lt;/servlet&gt;\n * </pre>\n * <p>\n * The init parameter 'config-file' can be used to specify the path (and\n * filename) of your Quartz properties file. If you leave out this parameter,\n * the default (\"quartz.properties\") will be used.\n * </p>\n *\n * <p>\n * The init parameter 'shutdown-on-unload' can be used to specify whether you\n * want scheduler.shutdown() called when the servlet is unloaded (usually when\n * the application server is being shutdown). Possible values are \"true\" or\n * \"false\". The default is \"true\".\n * </p>\n *\n * <p>\n * The init parameter 'wait-on-shutdown' has effect when \n * 'shutdown-on-unload' is specified \"true\", and indicates whether you\n * want scheduler.shutdown(true) called when the listener is unloaded (usually when\n * the application server is being shutdown).  Passing \"true\" to the shutdown() call\n * causes the scheduler to wait for existing jobs to complete. Possible values are \n * \"true\" or \"false\". The default is \"false\".\n * </p>\n *\n * <p>\n * The init parameter 'start-scheduler-on-load' can be used to specify whether\n * you want the scheduler.start() method called when the servlet is first loaded.\n * If set to false, your application will need to call the start() method before\n * the scheduler begins to run and process jobs. Possible values are \"true\" or\n * \"false\". The default is \"true\", which means the scheduler is started.\n * </p>\n *\n * A StdSchedulerFactory instance is stored into the ServletContext. You can gain access\n * to the factory from a ServletContext instance like this:\n * <br>\n * <pre>\n *     StdSchedulerFactory factory = (StdSchedulerFactory) ctx\n *                .getAttribute(QuartzFactoryServlet.QUARTZ_FACTORY_KEY);</pre>\n * <p>\n * The init parameter 'servlet-context-factory-key' can be used to override the\n * name under which the StdSchedulerFactory is stored into the ServletContext, in \n * which case you will want to use this name rather than \n * <code>QuartzFactoryServlet.QUARTZ_FACTORY_KEY</code> in the above example.\n * </p>\n * \n * <p>\n * The init parameter 'scheduler-context-servlet-context-key' if set, the \n * ServletContext will be stored in the SchedulerContext under the given key\n * name (and will therefore be available to jobs during execution). \n * </p>\n * \n * <p>\n * The init parameter 'start-delay-seconds' can be used to specify the amount\n * of time to wait after initializing the scheduler before scheduler.start()\n * is called.\n * </p>\n *\n * Once you have the factory instance, you can retrieve the Scheduler instance by calling\n * <code>getScheduler()</code> on the factory.\n *\n * @author James House\n * @author Chuck Cavaness\n */\npublic class QuartzInitializerServlet extends HttpServlet {\n\n    /**\n     * \n     */\n    private static final long serialVersionUID = 1L;\n\n    public static final String QUARTZ_FACTORY_KEY = \"org.quartz.impl.StdSchedulerFactory.KEY\";\n\n    private boolean performShutdown = true;\n    private boolean waitOnShutdown = false;\n\n    private transient Scheduler scheduler = null;\n\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    @Override\n    public void init(ServletConfig cfg) throws jakarta.servlet.ServletException {\n        super.init(cfg);\n\n        log(\"Quartz Initializer Servlet loaded, initializing Scheduler...\");\n\n        StdSchedulerFactory factory;\n        try {\n\n            String configFile = cfg.getInitParameter(\"config-file\");\n            String shutdownPref = cfg.getInitParameter(\"shutdown-on-unload\");\n\n            if (shutdownPref != null) {\n                performShutdown = Boolean.parseBoolean(shutdownPref);\n            }\n            String shutdownWaitPref = cfg.getInitParameter(\"wait-on-shutdown\");\n            if (shutdownPref != null) {\n                waitOnShutdown  = Boolean.parseBoolean(shutdownWaitPref);\n            }\n\n            factory = getSchedulerFactory(configFile);\n            \n            // Always want to get the scheduler, even if it isn't starting, \n            // to make sure it is both initialized and registered.\n            scheduler = factory.getScheduler();\n            \n            // Should the Scheduler being started now or later\n            String startOnLoad = cfg\n                    .getInitParameter(\"start-scheduler-on-load\");\n\n            int startDelay = 0;\n            String startDelayS = cfg.getInitParameter(\"start-delay-seconds\");\n            try {\n                if(startDelayS != null && !startDelayS.trim().isEmpty())\n                    startDelay = Integer.parseInt(startDelayS);\n            } catch(Exception e) {\n                log(\"Cannot parse value of 'start-delay-seconds' to an integer: \" + startDelayS + \", defaulting to 5 seconds.\", e);\n                startDelay = 5;\n            }\n            \n            /*\n             * If the \"start-scheduler-on-load\" init-parameter is not specified,\n             * the scheduler will be started. This is to maintain backwards\n             * compatability.\n             */\n            if (startOnLoad == null || (Boolean.parseBoolean(startOnLoad))) {\n                if(startDelay <= 0) {\n                    // Start now\n                    scheduler.start();\n                    log(\"Scheduler has been started...\");\n                }\n                else {\n                    // Start delayed\n                    scheduler.startDelayed(startDelay);\n                    log(\"Scheduler will start in \" + startDelay + \" seconds.\");\n                }\n            } else {\n                log(\"Scheduler has not been started. Use scheduler.start()\");\n            }\n\n            String factoryKey = cfg.getInitParameter(\"servlet-context-factory-key\");\n            if (factoryKey == null) {\n                factoryKey = QUARTZ_FACTORY_KEY;\n            }\n            \n            log(\"Storing the Quartz Scheduler Factory in the servlet context at key: \"\n                    + factoryKey);\n            cfg.getServletContext().setAttribute(factoryKey, factory);\n            \n            \n            String servletCtxKey = cfg.getInitParameter(\"scheduler-context-servlet-context-key\");\n            if (servletCtxKey != null) {\n                log(\"Storing the ServletContext in the scheduler context at key: \"\n                        + servletCtxKey);\n                scheduler.getContext().put(servletCtxKey, cfg.getServletContext());\n            }\n\n        } catch (Exception e) {\n            log(\"Quartz Scheduler failed to initialize: \" + e);\n            throw new ServletException(e);\n        }\n    }\n\n    protected StdSchedulerFactory getSchedulerFactory(String configFile)\n            throws SchedulerException {\n        StdSchedulerFactory factory;\n        // get Properties\n        if (configFile != null) {\n            factory = new StdSchedulerFactory(configFile);\n        } else {\n            factory = new StdSchedulerFactory();\n        }\n        return factory;\n    }\n\n    @Override\n    public void destroy() {\n\n        if (!performShutdown) {\n            return;\n        }\n\n        try {\n            if (scheduler != null) {\n                scheduler.shutdown(waitOnShutdown);\n            }\n        } catch (Exception e) {\n            log(\"Quartz Scheduler failed to shutdown cleanly: \" + e);\n            e.printStackTrace();\n        }\n\n        log(\"Quartz Scheduler successful shutdown.\");\n    }\n\n    @Override\n    public void doPost(HttpServletRequest request, HttpServletResponse response)\n        throws ServletException, IOException {\n        response.sendError(HttpServletResponse.SC_FORBIDDEN);\n    }\n\n    @Override\n    public void doGet(HttpServletRequest request, HttpServletResponse response)\n        throws ServletException, IOException {\n        response.sendError(HttpServletResponse.SC_FORBIDDEN);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/helpers/VersionPrinter.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.helpers;\n\nimport org.quartz.core.QuartzScheduler;\n\n/**\n * <p>\n * Prints the version of Quartz on stdout.\n * </p>\n * \n * @author James House\n */\npublic class VersionPrinter {\n\n    /**\n     * Private constructor because this is a pure utility class.\n     */\n    private VersionPrinter() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static void main(String[] args) {\n        System.out.println(\"Quartz version: \" + QuartzScheduler.getVersionMajor()\n                + \".\" + QuartzScheduler.getVersionMinor() + \".\"\n                + QuartzScheduler.getVersionIteration());\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/helpers/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.helpers</title>\n</head>\n<body>\n<p>Contains helper classes to make working with Quartz easier.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project\n  for more information.\n\n</body>\n</html>"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/DefaultThreadExecutor.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport org.quartz.spi.ThreadExecutor;\n\n/**\n * Schedules work on a newly spawned thread. This is the default Quartz\n * behavior.\n *\n * @author matt.accola\n * @version $Revision$ $Date$\n */\npublic class DefaultThreadExecutor implements ThreadExecutor {\n\n    public void initialize() {\n    }\n\n    public void execute(Thread thread) {\n        thread.start();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/DirectSchedulerFactory.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.impl;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.core.JobRunShellFactory;\nimport org.quartz.core.QuartzScheduler;\nimport org.quartz.core.QuartzSchedulerResources;\nimport org.quartz.simpl.CascadingClassLoadHelper;\nimport org.quartz.simpl.RAMJobStore;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.quartz.spi.ThreadExecutor;\nimport org.quartz.spi.ThreadPool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * A singleton implementation of <code>{@link org.quartz.SchedulerFactory}</code>.\n * </p>\n *\n * <p>\n * Here are some examples of using this class:\n * </p>\n * <p>\n * To create a scheduler that does not write anything to the database (is not\n * persistent), you can call <code>createVolatileScheduler</code>:\n *\n * <pre>\n *  DirectSchedulerFactory.getInstance().createVolatileScheduler(10); // 10 threads * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler().start();\n * </pre>\n *\n *\n * <p>\n * Several create methods are provided for convenience. All create methods\n * eventually end up calling the create method with all the parameters:\n * </p>\n *\n * <pre>\n *  public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort)\n * </pre>\n *\n *\n * <p>\n * Here is an example of using this method:\n * </p>\n *  *\n *  * <pre>// create the thread pool SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, Thread.NORM_PRIORITY); threadPool.initialize(); * // create the job store JobStore jobStore = new RAMJobStore();\n *\n *  DirectSchedulerFactory.getInstance().createScheduler(\"My Quartz Scheduler\", \"My Instance\", threadPool, jobStore, \"localhost\", 1099); * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler(\"My Quartz Scheduler\", \"My Instance\").start();\n * </pre>\n *\n *\n * <p>\n * You can also use a JDBCJobStore instead of the RAMJobStore:\n * </p>\n *\n * <pre>\n *  DBConnectionManager.getInstance().addConnectionProvider(\"someDatasource\", new JNDIConnectionProvider(\"someDatasourceJNDIName\"));\n *\n *  JobStoreTX jdbcJobStore = new JobStoreTX(); jdbcJobStore.setDataSource(\"someDatasource\"); jdbcJobStore.setPostgresStyleBlobs(true); jdbcJobStore.setTablePrefix(\"QRTZ_\"); jdbcJobStore.setInstanceId(\"My Instance\");\n * </pre>\n *\n * @author Mohammad Rezaei\n * @author James House\n *\n * @see JobStore\n * @see ThreadPool\n */\npublic class DirectSchedulerFactory implements SchedulerFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constants.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    public static final String DEFAULT_INSTANCE_ID = \"SIMPLE_NON_CLUSTERED\";\n\n    public static final String DEFAULT_SCHEDULER_NAME = \"SimpleQuartzScheduler\";\n\n    private static final boolean DEFAULT_JMX_EXPORT = false;\n\n    private static final String DEFAULT_JMX_OBJECTNAME = null;\n\n    private static final DefaultThreadExecutor DEFAULT_THREAD_EXECUTOR = new DefaultThreadExecutor();\n\n    private static final int DEFAULT_BATCH_MAX_SIZE = 1;\n\n    private static final long DEFAULT_BATCH_TIME_WINDOW = 0L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private boolean initialized = false;\n\n    private static final DirectSchedulerFactory instance = new DirectSchedulerFactory();\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * Constructor\n     */\n    protected DirectSchedulerFactory() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static DirectSchedulerFactory getInstance() {\n        return instance;\n    }\n\n    /**\n     * Creates an in memory job store (<code>{@link RAMJobStore}</code>)\n     * The thread priority is set to Thread.NORM_PRIORITY\n     *\n     * @param maxThreads\n     *          The number of threads in the thread pool\n     * @throws SchedulerException\n     *           if initialization failed.\n     */\n    public void createVolatileScheduler(int maxThreads)\n        throws SchedulerException {\n        SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads,\n                Thread.NORM_PRIORITY);\n        JobStore jobStore = new RAMJobStore();\n        this.createScheduler(threadPool, jobStore);\n    }\n\n\n    /**\n     * Creates a proxy to a remote scheduler. This scheduler can be retrieved\n     * via {@link DirectSchedulerFactory#getScheduler()}\n     *\n     * @param rmiHost\n     *          The hostname for remote scheduler\n     * @param rmiPort\n     *          Port for the remote scheduler. The default RMI port is 1099.\n     * @throws SchedulerException\n     *           if the remote scheduler could not be reached.\n     */\n    public void createRemoteScheduler(String rmiHost, int rmiPort)\n        throws SchedulerException {\n        createRemoteScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID,\n                rmiHost, rmiPort);\n    }\n\n    /**\n     * Same as\n     * {@link DirectSchedulerFactory#createRemoteScheduler(String rmiHost, int rmiPort)},\n     * with the addition of specifying the scheduler name and instance ID. This\n     * scheduler can only be retrieved via\n     * {@link DirectSchedulerFactory#getScheduler(String)}\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param rmiHost\n     *          The hostname for remote scheduler\n     * @param rmiPort\n     *          Port for the remote scheduler. The default RMI port is 1099.\n     * @throws SchedulerException\n     *           if the remote scheduler could not be reached.\n     */\n    public void createRemoteScheduler(String schedulerName,\n            String schedulerInstanceId, String rmiHost, int rmiPort)\n        throws SchedulerException {\n        createRemoteScheduler(schedulerName,\n                schedulerInstanceId, null, rmiHost, rmiPort);\n    }\n\n    /**\n     * Same as\n     * {@link DirectSchedulerFactory#createRemoteScheduler(String rmiHost, int rmiPort)},\n     * with the addition of specifying the scheduler name, instance ID, and rmi\n     * bind name. This scheduler can only be retrieved via\n     * {@link DirectSchedulerFactory#getScheduler(String)}\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param rmiBindName\n     *          The name of the remote scheduler in the RMI repository.  If null\n     *          defaults to the generated unique identifier.\n     * @param rmiHost\n     *          The hostname for remote scheduler\n     * @param rmiPort\n     *          Port for the remote scheduler. The default RMI port is 1099.\n     * @throws SchedulerException\n     *           if the remote scheduler could not be reached.\n     */\n    public void createRemoteScheduler(String schedulerName,\n            String schedulerInstanceId, String rmiBindName, String rmiHost, int rmiPort)\n        throws SchedulerException {\n\n        String uid = (rmiBindName != null) ? rmiBindName :\n            QuartzSchedulerResources.getUniqueIdentifier(\n                schedulerName, schedulerInstanceId);\n\n        RemoteScheduler remoteScheduler = new RemoteScheduler(uid, rmiHost, rmiPort);\n\n        SchedulerRepository schedRep = SchedulerRepository.getInstance();\n        schedRep.bind(remoteScheduler);\n        initialized = true;\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool and job store. This\n     * scheduler can be retrieved via\n     * {@link DirectSchedulerFactory#getScheduler()}\n     *\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(ThreadPool threadPool, JobStore jobStore)\n        throws SchedulerException {\n        createScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID,\n                threadPool, jobStore);\n    }\n\n    /**\n     * Same as\n     * {@link DirectSchedulerFactory#createScheduler(ThreadPool threadPool, JobStore jobStore)},\n     * with the addition of specifying the scheduler name and instance ID. This\n     * scheduler can only be retrieved via\n     * {@link DirectSchedulerFactory#getScheduler(String)}\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n            String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore)\n        throws SchedulerException {\n        createScheduler(schedulerName, schedulerInstanceId, threadPool,\n                jobStore, null, 0, -1, -1);\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool and job store and\n     * binds it to RMI.\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @param rmiRegistryHost\n     *          The hostname to register this scheduler with for RMI. Can use\n     *          \"null\" if no RMI is required.\n     * @param rmiRegistryPort\n     *          The port for RMI. Typically 1099.\n     * @param idleWaitTime\n     *          The idle wait time in milliseconds. You can specify \"-1\" for\n     *          the default value, which is currently 30000 ms.\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n            String schedulerInstanceId, ThreadPool threadPool,\n            JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort,\n            long idleWaitTime, long dbFailureRetryInterval)\n        throws SchedulerException {\n        createScheduler(schedulerName,\n                schedulerInstanceId, threadPool,\n                jobStore, null, // plugins\n                rmiRegistryHost, rmiRegistryPort,\n                idleWaitTime, dbFailureRetryInterval,\n                DEFAULT_JMX_EXPORT, DEFAULT_JMX_OBJECTNAME);\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool, job store, and\n     * plugins, and binds it to RMI.\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @param schedulerPluginMap\n     *          Map from a <code>String</code> plugin names to\n     *          <code>{@link org.quartz.spi.SchedulerPlugin}</code>s.  Can use\n     *          \"null\" if no plugins are required.\n     * @param rmiRegistryHost\n     *          The hostname to register this scheduler with for RMI. Can use\n     *          \"null\" if no RMI is required.\n     * @param rmiRegistryPort\n     *          The port for RMI. Typically 1099.\n     * @param idleWaitTime\n     *          The idle wait time in milliseconds. You can specify \"-1\" for\n     *          the default value, which is currently 30000 ms.\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n            String schedulerInstanceId, ThreadPool threadPool,\n            JobStore jobStore, Map<String, SchedulerPlugin> schedulerPluginMap,\n            String rmiRegistryHost, int rmiRegistryPort,\n            long idleWaitTime, long dbFailureRetryInterval,\n            boolean jmxExport, String jmxObjectName)\n        throws SchedulerException {\n        createScheduler(schedulerName, schedulerInstanceId, threadPool,\n                DEFAULT_THREAD_EXECUTOR, jobStore, schedulerPluginMap,\n                rmiRegistryHost, rmiRegistryPort, idleWaitTime,\n                dbFailureRetryInterval, jmxExport, jmxObjectName);\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool, job store, and\n     * plugins, and binds it to RMI.\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param threadExecutor\n     *          The thread executor for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @param schedulerPluginMap\n     *          Map from a <code>String</code> plugin names to\n     *          <code>{@link org.quartz.spi.SchedulerPlugin}</code>s.  Can use\n     *          \"null\" if no plugins are required.\n     * @param rmiRegistryHost\n     *          The hostname to register this scheduler with for RMI. Can use\n     *          \"null\" if no RMI is required.\n     * @param rmiRegistryPort\n     *          The port for RMI. Typically 1099.\n     * @param idleWaitTime\n     *          The idle wait time in milliseconds. You can specify \"-1\" for\n     *          the default value, which is currently 30000 ms.\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n            String schedulerInstanceId, ThreadPool threadPool,\n            ThreadExecutor threadExecutor,\n            JobStore jobStore, Map<String, SchedulerPlugin> schedulerPluginMap,\n            String rmiRegistryHost, int rmiRegistryPort,\n            long idleWaitTime, long dbFailureRetryInterval,\n            boolean jmxExport, String jmxObjectName)\n        throws SchedulerException {\n        createScheduler(schedulerName, schedulerInstanceId, threadPool,\n                DEFAULT_THREAD_EXECUTOR, jobStore, schedulerPluginMap,\n                rmiRegistryHost, rmiRegistryPort, idleWaitTime,\n                dbFailureRetryInterval, jmxExport, jmxObjectName, DEFAULT_BATCH_MAX_SIZE, DEFAULT_BATCH_TIME_WINDOW);\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool, job store, and\n     * plugins, and binds it to RMI.\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param threadExecutor\n     *          The thread executor for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @param schedulerPluginMap\n     *          Map from a <code>String</code> plugin names to\n     *          <code>{@link org.quartz.spi.SchedulerPlugin}</code>s.  Can use\n     *          \"null\" if no plugins are required.\n     * @param rmiRegistryHost\n     *          The hostname to register this scheduler with for RMI. Can use\n     *          \"null\" if no RMI is required.\n     * @param rmiRegistryPort\n     *          The port for RMI. Typically 1099.\n     * @param idleWaitTime\n     *          The idle wait time in milliseconds. You can specify \"-1\" for\n     *          the default value, which is currently 30000 ms.\n     * @param maxBatchSize\n     *          The maximum batch size of triggers, when acquiring them\n     * @param batchTimeWindow\n     *          The time window for which it is allowed to \"pre-acquire\" triggers to fire\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n            String schedulerInstanceId, ThreadPool threadPool,\n            ThreadExecutor threadExecutor,\n            JobStore jobStore, Map<String, SchedulerPlugin> schedulerPluginMap,\n            String rmiRegistryHost, int rmiRegistryPort,\n            long idleWaitTime, long dbFailureRetryInterval,\n            boolean jmxExport, String jmxObjectName, int maxBatchSize, long batchTimeWindow)\n        throws SchedulerException {\n\n        createScheduler(schedulerName, schedulerInstanceId,\n                threadPool, threadExecutor,\n                jobStore, schedulerPluginMap,\n                rmiRegistryHost, rmiRegistryPort,\n                idleWaitTime, dbFailureRetryInterval,\n                jmxExport, jmxObjectName,\n                maxBatchSize, batchTimeWindow,\n                false);\n    }\n\n    /**\n     * Creates a scheduler using the specified thread pool, job store, and\n     * plugins, and binds it to RMI.\n     *\n     * @param schedulerName\n     *          The name for the scheduler.\n     * @param schedulerInstanceId\n     *          The instance ID for the scheduler.\n     * @param threadPool\n     *          The thread pool for executing jobs\n     * @param threadExecutor\n     *          The thread executor for executing jobs\n     * @param jobStore\n     *          The type of job store\n     * @param schedulerPluginMap\n     *          Map from a <code>String</code> plugin names to\n     *          <code>{@link org.quartz.spi.SchedulerPlugin}</code>s.  Can use\n     *          \"null\" if no plugins are required.\n     * @param rmiRegistryHost\n     *          The hostname to register this scheduler with for RMI. Can use\n     *          \"null\" if no RMI is required.\n     * @param rmiRegistryPort\n     *          The port for RMI. Typically 1099.\n     * @param idleWaitTime\n     *          The idle wait time in milliseconds. You can specify \"-1\" for\n     *          the default value, which is currently 30000 ms.\n     * @param maxBatchSize\n     *          The maximum batch size of triggers, when acquiring them\n     * @param batchTimeWindow\n     *          The time window for which it is allowed to \"pre-acquire\" triggers to fire\n     * @param makeSchedThreadDaemon\n     *          Make the SchedulerThread a daemon thread.\n     * @throws SchedulerException\n     *           if initialization failed\n     */\n    public void createScheduler(String schedulerName,\n                                String schedulerInstanceId, ThreadPool threadPool,\n                                ThreadExecutor threadExecutor,\n                                JobStore jobStore, Map<String, SchedulerPlugin> schedulerPluginMap,\n                                String rmiRegistryHost, int rmiRegistryPort,\n                                long idleWaitTime, long dbFailureRetryInterval,\n                                boolean jmxExport, String jmxObjectName,\n                                int maxBatchSize, long batchTimeWindow,\n                                boolean makeSchedThreadDaemon)\n            throws SchedulerException {\n\n        // Currently only one run-shell factory is available...\n        JobRunShellFactory jrsf = new StdJobRunShellFactory();\n\n        // Fire everything up\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n        threadPool.setInstanceName(schedulerName);\n        threadPool.initialize();\n        \n        QuartzSchedulerResources qrs = new QuartzSchedulerResources();\n\n        qrs.setName(schedulerName);\n        qrs.setInstanceId(schedulerInstanceId);\n        qrs.setMakeSchedulerThreadDaemon(makeSchedThreadDaemon);\n        SchedulerDetailsSetter.setDetails(threadPool, schedulerName, schedulerInstanceId);\n        qrs.setJobRunShellFactory(jrsf);\n        qrs.setThreadPool(threadPool);\n        qrs.setThreadExecutor(threadExecutor);\n        qrs.setJobStore(jobStore);\n        qrs.setMaxBatchSize(maxBatchSize);\n        qrs.setBatchTimeWindow(batchTimeWindow);\n        qrs.setRMIRegistryHost(rmiRegistryHost);\n        qrs.setRMIRegistryPort(rmiRegistryPort);\n        qrs.setJMXExport(jmxExport);\n        if (jmxObjectName != null) {\n           qrs.setJMXObjectName(jmxObjectName);\n        }\n        \n        // add plugins\n        if (schedulerPluginMap != null) {\n            for (SchedulerPlugin schedulerPlugin : schedulerPluginMap.values()) {\n                qrs.addSchedulerPlugin(schedulerPlugin);\n            }\n        }\n\n        QuartzScheduler qs = new QuartzScheduler(qrs, idleWaitTime, dbFailureRetryInterval);\n\n        ClassLoadHelper cch = new CascadingClassLoadHelper();\n        cch.initialize();\n\n        SchedulerDetailsSetter.setDetails(jobStore, schedulerName, schedulerInstanceId);\n\n        jobStore.initialize(cch, qs.getSchedulerSignaler());\n\n        Scheduler scheduler = new StdScheduler(qs);\n\n        jrsf.initialize(scheduler);\n\n        qs.initialize();\n        \n\n        // Initialize plugins now that we have a Scheduler instance.\n        if (schedulerPluginMap != null) {\n            for (Entry<String, SchedulerPlugin> pluginEntry : schedulerPluginMap.entrySet()) {\n                pluginEntry.getValue().initialize(pluginEntry.getKey(), scheduler, cch);\n            }\n        }\n\n        getLog().info(\"Quartz scheduler '{}\", scheduler.getSchedulerName());\n\n        getLog().info(\"Quartz scheduler version: {}\", qs.getVersion());\n\n        SchedulerRepository schedRep = SchedulerRepository.getInstance();\n\n        qs.addNoGCObject(schedRep); // prevents the repository from being\n        // garbage collected\n\n        schedRep.bind(scheduler);\n        \n        initialized = true;\n    }\n\n    /*\n     * public void registerSchedulerForRmi(String schedulerName, String\n     * schedulerId, String registryHost, int registryPort) throws\n     * SchedulerException, RemoteException { QuartzScheduler scheduler =\n     * (QuartzScheduler) this.getScheduler(); scheduler.bind(registryHost,\n     * registryPort); }\n     */\n\n    /**\n     * <p>\n     * Returns a handle to the Scheduler produced by this factory.\n     * </p>\n     *\n     * <p>\n     * you must call createRemoteScheduler or createScheduler methods before\n     * calling getScheduler()\n     * </p>\n     */\n    public Scheduler getScheduler() throws SchedulerException {\n        if (!initialized) {\n            throw new SchedulerException(\n                \"you must call createRemoteScheduler or createScheduler methods before calling getScheduler()\");\n        }\n\n        return getScheduler(DEFAULT_SCHEDULER_NAME);\n    }\n\n    /**\n     * <p>\n     * Returns a handle to the Scheduler with the given name, if it exists.\n     * </p>\n     */\n    public Scheduler getScheduler(String schedName) throws SchedulerException {\n        SchedulerRepository schedRep = SchedulerRepository.getInstance();\n\n        return schedRep.lookup(schedName);\n    }\n\n    /**\n     * <p>\n     * Returns a handle to all known Schedulers (made by any\n     * StdSchedulerFactory instance.).\n     * </p>\n     */\n    public Collection<Scheduler> getAllSchedulers() throws SchedulerException {\n        return SchedulerRepository.getInstance().lookupAll();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/JobDetailImpl.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.quartz.Scheduler;\nimport org.quartz.StatefulJob;\nimport org.quartz.Trigger;\nimport org.quartz.utils.ClassUtils;\n\n\n/**\n * <p>\n * Conveys the detail properties of a given <code>Job</code> instance.\n * </p>\n * \n * <p>\n * Quartz does not store an actual instance of a <code>Job</code> class, but\n * instead allows you to define an instance of one, through the use of a <code>JobDetail</code>.\n * </p>\n * \n * <p>\n * <code>Job</code>s have a name and group associated with them, which\n * should uniquely identify them within a single <code>{@link Scheduler}</code>.\n * </p>\n * \n * <p>\n * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code>s\n * are scheduled. Many <code>Trigger</code>s can point to the same <code>Job</code>,\n * but a single <code>Trigger</code> can only point to one <code>Job</code>.\n * </p>\n * \n * @see Job\n * @see StatefulJob\n * @see JobDataMap\n * @see Trigger\n * \n * @author James House\n * @author Sharada Jambula\n */\n@SuppressWarnings(\"deprecation\")\npublic class JobDetailImpl implements Cloneable, java.io.Serializable, JobDetail {\n\n    private static final long serialVersionUID = -6069784757781506897L;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private String name;\n\n    private String group = Scheduler.DEFAULT_GROUP;\n\n    private String description;\n\n    private Class<? extends Job> jobClass;\n\n    private JobDataMap jobDataMap;\n\n    private boolean durability = false;\n\n    private boolean shouldRecover = false;\n\n    private transient JobKey key = null;\n\n    /*\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    *\n    * Constructors.\n    *\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    */\n\n    /**\n     * <p>\n     * Create a <code>JobDetail</code> with no specified name or group, and\n     * the default settings of all the other properties.\n     * </p>\n     * \n     * <p>\n     * Note that the {@link #setName(String)},{@link #setGroup(String)}and\n     * {@link #setJobClass(Class)}methods must be called before the job can be\n     * placed into a {@link Scheduler}\n     * </p>\n     */\n    public JobDetailImpl() {\n        // do nothing...\n    }\n\n    /**\n     * <p>\n     * Create a <code>JobDetail</code> with the given name, given class, default group, \n     * and the default settings of all the other properties.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     *              \n     * @deprecated use {@link JobBuilder}              \n     */\n    @Deprecated\n    public JobDetailImpl(String name, Class<? extends Job> jobClass) {\n        this(name, null, jobClass);\n    }\n\n    /**\n     * <p>\n     * Create a <code>JobDetail</code> with the given name, group and class, \n     * and the default settings of all the other properties.\n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     *              \n     * @deprecated use {@link JobBuilder}              \n     */\n    @Deprecated\n    public JobDetailImpl(String name, String group, Class<? extends Job> jobClass) {\n        setName(name);\n        setGroup(group);\n        setJobClass(jobClass);\n    }\n\n    /**\n     * <p>\n     * Create a <code>JobDetail</code> with the given name, and group, and\n     * the given settings of all the other properties.\n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     *              \n     * @deprecated use {@link JobBuilder}              \n     */\n    @Deprecated\n    public JobDetailImpl(String name, String group, Class<? extends Job> jobClass,\n                     boolean durability, boolean recover) {\n        setName(name);\n        setGroup(group);\n        setJobClass(jobClass);\n        setDurability(durability);\n        setRequestsRecovery(recover);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name of this <code>Job</code>.\n     * </p>\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * <p>\n     * Set the name of this <code>Job</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty.\n     */\n    public void setName(String name) {\n        if (name == null || name.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Job name cannot be empty.\");\n        }\n\n        this.name = name;\n        this.key = null;\n    }\n\n    /**\n     * <p>\n     * Get the group of this <code>Job</code>.\n     * </p>\n     */\n    public String getGroup() {\n        return group;\n    }\n\n    /**\n     * <p>\n     * Set the group of this <code>Job</code>.\n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if the group is an empty string.\n     */\n    public void setGroup(String group) {\n        if (group != null && group.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Group name cannot be empty.\");\n        }\n\n        if (group == null) {\n            group = Scheduler.DEFAULT_GROUP;\n        }\n\n        this.group = group;\n        this.key = null;\n    }\n\n    /**\n     * <p>\n     * Returns the 'full name' of the <code>JobDetail</code> in the format\n     * \"group.name\".\n     * </p>\n     */\n    public String getFullName() {\n        return group + \".\" + name;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#getKey()\n     */\n    public JobKey getKey() {\n        if(key == null) {\n            if(getName() == null)\n                return null;\n            key = new JobKey(getName(), getGroup());\n        }\n\n        return key;\n    }\n    \n    public void setKey(JobKey key) {\n        if(key == null)\n            throw new IllegalArgumentException(\"Key cannot be null!\");\n\n        setName(key.getName());\n        setGroup(key.getGroup());\n        this.key = key;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#getDescription()\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * <p>\n     * Set a description for the <code>Job</code> instance - may be useful\n     * for remembering/displaying the purpose of the job, though the\n     * description has no meaning to Quartz.\n     * </p>\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#getJobClass()\n     */\n    public Class<? extends Job> getJobClass() {\n        return jobClass;\n    }\n\n    /**\n     * <p>\n     * Set the instance of <code>Job</code> that will be executed.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if jobClass is null or the class is not a <code>Job</code>.\n     */\n    public void setJobClass(Class<? extends Job> jobClass) {\n        if (jobClass == null) {\n            throw new IllegalArgumentException(\"Job class cannot be null.\");\n        }\n\n        if (!Job.class.isAssignableFrom(jobClass)) {\n            throw new IllegalArgumentException(\n                    \"Job class must implement the Job interface.\");\n        }\n\n        this.jobClass = jobClass;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#getJobDataMap()\n     */\n    public JobDataMap getJobDataMap() {\n        if (jobDataMap == null) {\n            jobDataMap = new JobDataMap();\n        }\n        return jobDataMap;\n    }\n\n    /**\n     * <p>\n     * Set the <code>JobDataMap</code> to be associated with the <code>Job</code>.\n     * </p>\n     */\n    public void setJobDataMap(JobDataMap jobDataMap) {\n        this.jobDataMap = jobDataMap;\n    }\n\n    /**\n     * <p>\n     * Set whether or not the <code>Job</code> should remain stored after it\n     * is orphaned (no <code>{@link Trigger}s</code> point to it).\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     */\n    public void setDurability(boolean durability) {\n        this.durability = durability;\n    }\n\n    /**\n     * <p>\n     * Set whether or not the <code>Scheduler</code> should re-execute\n     * the <code>Job</code> if a 'recovery' or 'fail-over' situation is\n     * encountered.\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>false</code>.\n     * </p>\n     * \n     * @see JobExecutionContext#isRecovering()\n     */\n    public void setRequestsRecovery(boolean shouldRecover) {\n        this.shouldRecover = shouldRecover;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#isDurable()\n     */\n    public boolean isDurable() {\n        return durability;\n    }\n\n    /**\n     * @return whether the associated Job class carries the {@link PersistJobDataAfterExecution} annotation.\n     */\n    public boolean isPersistJobDataAfterExecution() {\n\n        return ClassUtils.isAnnotationPresent(jobClass, PersistJobDataAfterExecution.class);\n    }\n\n    /**\n     * @return whether the associated Job class carries the {@link DisallowConcurrentExecution} annotation.\n     */\n    public boolean isConcurrentExecutionDisallowed() {\n        \n        return ClassUtils.isAnnotationPresent(jobClass, DisallowConcurrentExecution.class);\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.JobDetailI#requestsRecovery()\n     */\n    public boolean requestsRecovery() {\n        return shouldRecover;\n    }\n\n    /**\n     * <p>\n     * Return a simple string representation of this object.\n     * </p>\n     */\n    @Override\n    public String toString() {\n        return \"JobDetail '\" + getFullName() + \"':  jobClass: '\"\n                + ((getJobClass() == null) ? null : getJobClass().getName())\n                + \" concurrentExecutionDisallowed: \" + isConcurrentExecutionDisallowed() \n                + \" persistJobDataAfterExecution: \" + isPersistJobDataAfterExecution() \n                + \" isDurable: \" + isDurable() + \" requestsRecovers: \" + requestsRecovery();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof JobDetail)) {\n            return false;\n        }\n\n        JobDetail other = (JobDetail) obj;\n\n        if(other.getKey() == null || getKey() == null)\n            return false;\n\n        return other.getKey().equals(getKey());\n    }\n\n    @Override\n    public int hashCode() {\n        JobKey key = getKey();\n        return key == null ? 0 : getKey().hashCode();\n    }\n    \n    @Override\n    public Object clone() {\n        JobDetailImpl copy;\n        try {\n            copy = (JobDetailImpl) super.clone();\n            if (jobDataMap != null) {\n                copy.jobDataMap = (JobDataMap) jobDataMap.clone();\n            }\n        } catch (CloneNotSupportedException ex) {\n            throw new IncompatibleClassChangeError(\"Not Cloneable.\");\n        }\n\n        return copy;\n    }\n\n    public JobBuilder getJobBuilder() {\n        return JobBuilder.newJob()\n            .ofType(getJobClass())\n            .requestRecovery(requestsRecovery())\n            .storeDurably(isDurable())\n            .usingJobData(getJobDataMap())\n            .withDescription(getDescription())\n            .withIdentity(getKey());\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/JobExecutionContextImpl.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport java.util.Date;\nimport java.util.HashMap;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Scheduler;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.TriggerFiredBundle;\n\n\npublic class JobExecutionContextImpl implements java.io.Serializable, JobExecutionContext {\n\n    private static final long serialVersionUID = -8139417614523942021L;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final transient Scheduler scheduler;\n\n    private final Trigger trigger;\n\n    private final JobDetail jobDetail;\n    \n    private final JobDataMap jobDataMap;\n\n    private final transient Job job;\n    \n    private final Calendar calendar;\n\n    private boolean recovering;\n\n    private int numRefires = 0;\n\n    private final Date fireTime;\n\n    private final Date scheduledFireTime;\n\n    private final Date prevFireTime;\n\n    private final Date nextFireTime;\n    \n    private long jobRunTime = -1;\n    \n    private Object result;\n    \n    private final HashMap<Object, Object> data = new HashMap<>();\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a JobExecutionContext with the given context data.\n     * </p>\n     */\n    public JobExecutionContextImpl(Scheduler scheduler,\n            TriggerFiredBundle firedBundle, Job job) {\n        this.scheduler = scheduler;\n        this.trigger = firedBundle.getTrigger();\n        this.calendar = firedBundle.getCalendar();\n        this.jobDetail = firedBundle.getJobDetail();\n        this.job = job;\n        this.recovering = firedBundle.isRecovering();\n        this.fireTime = firedBundle.getFireTime();\n        this.scheduledFireTime = firedBundle.getScheduledFireTime();\n        this.prevFireTime = firedBundle.getPrevFireTime();\n        this.nextFireTime = firedBundle.getNextFireTime();\n        \n        this.jobDataMap = new JobDataMap();\n        this.jobDataMap.putAll(jobDetail.getJobDataMap());\n        this.jobDataMap.putAll(trigger.getJobDataMap());\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * {@inheritDoc}\n     */\n    public Scheduler getScheduler() {\n        return scheduler;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Trigger getTrigger() {\n        return trigger;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Calendar getCalendar() {\n        return calendar;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public boolean isRecovering() {\n        return recovering;\n    }\n\n    public TriggerKey getRecoveringTriggerKey() {\n        if (isRecovering()) {\n            return new TriggerKey(jobDataMap.getString(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME),\n                                  jobDataMap.getString(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP));\n        } else {\n            throw new IllegalStateException(\"Not a recovering job\");\n        }\n    }\n    \n    public void incrementRefireCount() {\n        numRefires++;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public int getRefireCount() {\n        return numRefires;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public JobDataMap getMergedJobDataMap() {\n        return jobDataMap;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public JobDetail getJobDetail() {\n        return jobDetail;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Job getJobInstance() {\n        return job;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Date getFireTime() {\n        return fireTime;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Date getScheduledFireTime() {\n        return scheduledFireTime;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Date getPreviousFireTime() {\n        return prevFireTime;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    @Override\n    public String toString() {\n        return \"JobExecutionContext:\" + \" trigger: '\"\n                + getTrigger().getKey() + \" job: \"\n                + getJobDetail().getKey() + \" fireTime: '\" + getFireTime()\n                + \" scheduledFireTime: \" + getScheduledFireTime()\n                + \" previousFireTime: '\" + getPreviousFireTime()\n                + \" nextFireTime: \" + getNextFireTime() + \" isRecovering: \"\n                + isRecovering() + \" refireCount: \" + getRefireCount();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Object getResult() {\n        return result;\n    }\n    \n    /**\n     * {@inheritDoc}\n     */\n    public void setResult(Object result) {\n        this.result = result;\n    }\n    \n    /**\n     * {@inheritDoc}\n     */\n    public long getJobRunTime() {\n        return jobRunTime;\n    }\n    \n    /**\n     * @param jobRunTime The jobRunTime to set.\n     */\n    public void setJobRunTime(long jobRunTime) {\n        this.jobRunTime = jobRunTime;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void put(Object key, Object value) {\n        data.put(key, value);\n    }\n    \n    /**\n     * {@inheritDoc}\n     */\n    public Object get(Object key) {\n        return data.get(key);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public String getFireInstanceId() {\n        return ((OperableTrigger)trigger).getFireInstanceId();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/QuartzServer.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.listeners.SchedulerListenerSupport;\n\n/**\n * <p>\n * Instantiates an instance of Quartz Scheduler as a stand-alone program, if\n * the scheduler is configured for RMI it will be made available.\n * </p>\n *\n * <p>\n * The main() method of this class currently accepts 0 or 1 arguments, if there\n * is an argument, and its value is <code>\"console\"</code>, then the program\n * will print a short message on the console (std-out) and wait for the user to\n * type \"exit\" - at which time the scheduler will be shutdown.\n * </p>\n *\n * <p>\n * Future versions of this server should allow additional configuration for\n * responding to scheduler events by allowing the user to specify <code>{@link org.quartz.JobListener}</code>,\n * <code>{@link org.quartz.TriggerListener}</code> and <code>{@link org.quartz.SchedulerListener}</code>\n * classes.\n * </p>\n *\n * <p>\n * Please read the Quartz FAQ entries about RMI before asking questions in the\n * forums or mail-lists.\n * </p>\n *\n * @author James House\n */\npublic class QuartzServer extends SchedulerListenerSupport {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Scheduler sched = null;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    QuartzServer() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void serve(SchedulerFactory schedFact, boolean console)\n        throws Exception {\n        sched = schedFact.getScheduler();\n\n        sched.start();\n\n        try {\n            Thread.sleep(3000L);\n        } catch (Exception ignore) {\n        }\n\n        System.out.println(\"\\n*** The scheduler successfully started.\");\n\n        if (console) {\n            System.out.println(\"\\n\");\n            System.out\n                    .println(\"The scheduler will now run until you type \\\"exit\\\"\");\n            System.out\n                    .println(\"   If it was configured to export itself via RMI,\");\n            System.out.println(\"   then other process may now use it.\");\n\n            BufferedReader rdr = new BufferedReader(new InputStreamReader(\n                    System.in));\n\n            while (true) {\n                System.out.print(\"Type 'exit' to shutdown the server: \");\n                if (\"exit\".equals(rdr.readLine())) {\n                    break;\n                }\n            }\n\n            System.out.println(\"\\n...Shutting down server...\");\n\n            sched.shutdown(true);\n        }\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * SchedulerListener Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> when a serious error has\n     * occurred within the scheduler - such as repeated failures in the <code>JobStore</code>,\n     * or the inability to instantiate a <code>Job</code> instance when its\n     * <code>Trigger</code> has fired.\n     * </p>\n     *\n     * <p>\n     * The <code>getErrorCode()</code> method of the given SchedulerException\n     * can be used to determine more specific information about the type of\n     * error that was encountered.\n     * </p>\n     */\n    @Override\n    public void schedulerError(String msg, SchedulerException cause) {\n        System.err.println(\"*** \" + msg);\n        cause.printStackTrace();\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link Scheduler}</code> to inform the listener\n     * that it has shutdown.\n     * </p>\n     */\n    @Override\n    public void schedulerShutdown() {\n        System.out.println(\"\\n*** The scheduler is now shutdown.\");\n        sched = null;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Main Method.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static void main(String[] args) throws Exception {\n\n        //    //Configure Log4J\n        //    org.apache.log4j.PropertyConfigurator.configure(\n        //      System.getProperty(\"log4jConfigFile\", \"log4j.properties\"));\n\n        if (System.getSecurityManager() == null) {\n            System.setSecurityManager(new java.rmi.RMISecurityManager());\n        }\n\n        try {\n            QuartzServer server = new QuartzServer();\n            if (args.length == 0) {\n                server.serve(\n                    new org.quartz.impl.StdSchedulerFactory(), false);\n            } else if (args.length == 1 && args[0].equalsIgnoreCase(\"console\")) {\n                server.serve(new org.quartz.impl.StdSchedulerFactory(), true);\n            } else {\n                System.err.println(\"\\nUsage: QuartzServer [console]\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/RemoteMBeanScheduler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl;\n\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.management.Attribute;\nimport javax.management.AttributeList;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\nimport javax.management.openmbean.CompositeData;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.ListenerManager;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.UnableToInterruptJobException;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.core.jmx.JobDetailSupport;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.matchers.StringMatcher;\nimport org.quartz.spi.JobFactory;\n\n/**\n * <p>\n * An implementation of the <code>Scheduler</code> interface that remotely\n * proxies all method calls to the equivalent call on a given <code>QuartzScheduler</code>\n * instance, via JMX.\n * </p>\n * \n * <p>\n * A user must create a subclass to implement the actual connection to the remote \n * MBeanServer using their application specific connector.\n * </p>\n * @see org.quartz.Scheduler\n * @see org.quartz.core.QuartzScheduler\n */\npublic abstract class RemoteMBeanScheduler implements Scheduler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private ObjectName schedulerObjectName;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public RemoteMBeanScheduler() { \n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Properties.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    /**\n     * Get the name under which the Scheduler MBean is registered on the\n     * remote MBean server.\n     */\n    protected ObjectName getSchedulerObjectName() {\n        return schedulerObjectName;\n    }\n\n    /**\n     * Set the name under which the Scheduler MBean is registered on the\n     * remote MBean server.\n     */\n    public void setSchedulerObjectName(String schedulerObjectName)  throws SchedulerException {\n        try {\n            this.schedulerObjectName = new ObjectName(schedulerObjectName);\n        } catch (MalformedObjectNameException e) {\n            throw new SchedulerException(\"Failed to parse Scheduler MBean name: \" + schedulerObjectName, e);\n        }\n    }\n\n    /**\n     * Set the name under which the Scheduler MBean is registered on the\n     * remote MBean server.\n     */\n    public void setSchedulerObjectName(ObjectName schedulerObjectName)  throws SchedulerException {\n        this.schedulerObjectName = schedulerObjectName;\n    }\n\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Abstract methods.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Initialize this RemoteMBeanScheduler instance, connecting to the\n     * remote MBean server.\n     */\n    public abstract void initialize() throws SchedulerException;\n\n    /**\n     * Get the given attribute of the remote Scheduler MBean.\n     */\n    protected abstract Object getAttribute(\n            String attribute) throws SchedulerException;\n        \n    /**\n     * Get the given attributes of the remote Scheduler MBean.\n     */\n    protected abstract AttributeList getAttributes(String[] attributes)\n        throws SchedulerException;\n    \n    /**\n     * Invoke the given operation on the remote Scheduler MBean.\n     */\n    protected abstract Object invoke(\n        String operationName,\n        Object[] params,\n        String[] signature) throws SchedulerException;\n        \n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Returns the name of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerName() throws SchedulerException {\n        return (String)getAttribute(\"SchedulerName\");\n    }\n\n    /**\n     * <p>\n     * Returns the instance Id of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerInstanceId() throws SchedulerException {\n        return (String)getAttribute(\"SchedulerInstanceId\");\n    }\n\n    public SchedulerMetaData getMetaData() throws SchedulerException {\n        AttributeList attributeList =\n            getAttributes(\n                new String[] {\n                    \"SchedulerName\",\n                    \"SchedulerInstanceId\",\n                    \"StandbyMode\",\n                    \"Shutdown\",\n                    \"JobStoreClassName\",\n                    \"ThreadPoolClassName\",\n                    \"ThreadPoolSize\",\n                    \"Version\",\n                    \"PerformanceMetrics\"\n                });\n\n        try {\n            return new SchedulerMetaData(\n                    (String)getAttribute(attributeList, 0).getValue(),\n                    (String)getAttribute(attributeList, 1).getValue(),\n                    getClass(), true, false,\n                    (Boolean)getAttribute(attributeList, 2).getValue(),\n                    (Boolean)getAttribute(attributeList, 3).getValue(),\n                    null,\n                    Integer.parseInt(((Map)getAttribute(attributeList, 8).getValue()).get(\"JobsExecuted\").toString()),\n                    Class.forName((String)getAttribute(attributeList, 4).getValue()),\n                    false,\n                    false,\n                    Class.forName((String)getAttribute(attributeList, 5).getValue()),\n                    (Integer)getAttribute(attributeList, 6).getValue(),\n                    (String)getAttribute(attributeList, 7).getValue());\n        } catch (ClassNotFoundException e) {\n            throw new SchedulerException(e);\n        }\n    }\n\n    private Attribute getAttribute(AttributeList attributeList, int index) {\n        return (Attribute)attributeList.get(index);\n    }\n\n    /**\n     * <p>\n     * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.\n     * </p>\n     */\n    public SchedulerContext getContext() throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduler State Management Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void start() throws SchedulerException {\n        invoke(\"start\", new Object[] {}, new String[] {});\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void startDelayed(int seconds) throws SchedulerException {\n        invoke(\"startDelayed\", new Object[] {seconds}, new String[] {int.class.getName()});\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void standby() throws SchedulerException {\n        invoke(\"standby\", new Object[] {}, new String[] {});\n    }\n\n    /**\n     * Whether the scheduler has been started.  \n     * \n     * <p>\n     * Note: This only reflects whether <code>{@link #start()}</code> has ever\n     * been called on this Scheduler, so it will return <code>true</code> even \n     * if the <code>Scheduler</code> is currently in standby mode or has been \n     * since shutdown.\n     * </p>\n     * \n     * @see #start()\n     * @see #isShutdown()\n     * @see #isInStandbyMode()\n     */    \n    public boolean isStarted() throws SchedulerException {\n        return (Boolean) getAttribute(\"Started\");\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isInStandbyMode() throws SchedulerException {\n        return (Boolean)getAttribute(\"StandbyMode\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown() throws SchedulerException {\n        // Have to get the scheduler name before we actually call shutdown.\n        String schedulerName = getSchedulerName();\n        \n        invoke(\"shutdown\", new Object[] {}, new String[] {});\n        SchedulerRepository.getInstance().remove(schedulerName);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown(boolean waitForJobsToComplete) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isShutdown() throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduling-related Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public Date scheduleJob(JobDetail jobDetail, Trigger trigger)\n        throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public Date scheduleJob(Trigger trigger) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void addJob(JobDetail jobDetail, boolean replace)\n        throws SchedulerException {\n        invoke(\n            \"addJob\", \n            new Object[] { JobDetailSupport.toCompositeData(jobDetail), replace },\n            new String[] { CompositeData.class.getName(), boolean.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)\n            throws SchedulerException {\n        invoke(\n                \"addJob\",\n                new Object[] { JobDetailSupport.toCompositeData(jobDetail), replace , storeNonDurableWhileAwaitingScheduling},\n                new String[] { CompositeData.class.getName(), boolean.class.getName(), boolean.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public boolean deleteJob(JobKey jobKey)\n        throws SchedulerException {\n        return (Boolean)invoke(\n                \"deleteJob\",\n                new Object[] { jobKey.getName(), jobKey.getGroup() },\n                new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public boolean unscheduleJob(TriggerKey triggerKey)\n        throws SchedulerException {\n        return (Boolean)invoke(\n                \"unscheduleJob\",\n                new Object[] { triggerKey.getName(), triggerKey.getGroup() },\n                new String[] { String.class.getName(), String.class.getName() });\n    }\n\n\n    public boolean deleteJobs(List<JobKey> jobKeys) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    public void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    public void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    public boolean unscheduleJobs(List<TriggerKey> triggerKeys) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public Date rescheduleJob(TriggerKey triggerKey,\n            Trigger newTrigger) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n    \n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey) throws SchedulerException {\n        triggerJob(jobKey, null);\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException {\n        invoke(\n            \"pauseTrigger\", \n            new Object[] { triggerKey.getName(), triggerKey.getGroup() },\n            new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        String operation = null;\n        switch (matcher.getCompareWithOperator()) {\n            case EQUALS:\n                operation = \"pauseTriggerGroup\";\n                break;\n            case CONTAINS:\n                operation = \"pauseTriggersContaining\";\n                break;\n            case STARTS_WITH:\n                operation = \"pauseTriggersStartingWith\";\n                break;\n            case ENDS_WITH:\n                operation = \"pauseTriggersEndingWith\";\n            case ANYTHING:\n                operation = \"pauseTriggersAll\";\n        }\n\n        if (operation != null) {\n            invoke(\n                    operation,\n                    new Object[] { matcher.getCompareToValue() },\n                    new String[] { String.class.getName() });\n        } else {\n            throw new SchedulerException(\"Unsupported GroupMatcher kind for pausing triggers: \" + matcher.getCompareWithOperator());\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void pauseJob(JobKey jobKey) throws SchedulerException {\n        invoke(\n            \"pauseJob\", \n            new Object[] { jobKey.getName(), jobKey.getGroup() },\n            new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        String operation = null;\n        switch (matcher.getCompareWithOperator()) {\n            case EQUALS:\n                operation = \"pauseJobGroup\";\n                break;\n            case STARTS_WITH:\n                operation = \"pauseJobsStartingWith\";\n                break;\n            case ENDS_WITH:\n                operation = \"pauseJobsEndingWith\";\n                break;\n            case CONTAINS:\n                operation = \"pauseJobsContaining\";\n            case ANYTHING:\n                operation = \"pauseJobsAll\";\n        }\n\n        invoke(\n                operation,\n                new Object[] { matcher.getCompareToValue() },\n                new String[] { String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resumeTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        invoke(\n            \"resumeTrigger\", \n            new Object[] { triggerKey.getName(), triggerKey.getGroup() },\n            new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        String operation = null;\n        switch (matcher.getCompareWithOperator()) {\n            case EQUALS:\n                operation = \"resumeTriggerGroup\";\n                break;\n            case CONTAINS:\n                operation = \"resumeTriggersContaining\";\n                break;\n            case STARTS_WITH:\n                operation = \"resumeTriggersStartingWith\";\n                break;\n            case ENDS_WITH:\n                operation = \"resumeTriggersEndingWith\";\n            case ANYTHING:\n                operation = \"resumeTriggersAll\";\n        }\n\n        if (operation != null) {\n            invoke(\n                    operation,\n                    new Object[] { matcher.getCompareToValue() },\n                    new String[] { String.class.getName() });\n        } else {\n            throw new SchedulerException(\"Unsupported GroupMatcher kind for resuming triggers: \" + matcher.getCompareWithOperator());\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resumeJob(JobKey jobKey)\n        throws SchedulerException {\n        invoke(\n            \"resumeJob\", \n            new Object[] { jobKey.getName(), jobKey.getGroup() },\n            new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        String operation = null;\n        switch (matcher.getCompareWithOperator()) {\n            case EQUALS:\n                operation = \"resumeJobGroup\";\n                break;\n            case STARTS_WITH:\n                operation = \"resumeJobsStartingWith\";\n                break;\n            case ENDS_WITH:\n                operation = \"resumeJobsEndingWith\";\n                break;\n            case CONTAINS:\n                operation = \"resumeJobsContaining\";\n            case ANYTHING:\n                operation = \"resumeJobsAll\";\n        }\n\n        invoke(\n                operation,\n                new Object[] { matcher.getCompareToValue() },\n                new String[] { String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void pauseAll() throws SchedulerException {\n        invoke(\n            \"pauseAllTriggers\",\n            new Object[] { }, \n            new String[] { });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resumeAll() throws SchedulerException {\n        invoke(\n            \"resumeAllTriggers\",\n            new Object[] { }, \n            new String[] { });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getJobGroupNames() throws SchedulerException {\n        return (List<String>)getAttribute(\"JobGroupNames\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        if (matcher.getCompareWithOperator().equals(StringMatcher.StringOperatorName.EQUALS)) {\n            List<JobKey> keys = (List<JobKey>)invoke(\n                    \"getJobNames\",\n                    new Object[] { matcher.getCompareToValue() },\n                    new String[] { String.class.getName() });\n\n            return new HashSet<>(keys);\n        } else {\n            throw new SchedulerException(\"Only equals matcher are supported for looking up JobKeys\");\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<Trigger> getTriggersOfJob(JobKey jobKey) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getTriggerGroupNames() throws SchedulerException {\n        return (List<String>)getAttribute(\"TriggerGroupNames\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public JobDetail getJobDetail(JobKey jobKey) throws SchedulerException {\n        try {\n            return JobDetailSupport.newJobDetail((CompositeData)invoke(\n                    \"getJobDetail\",\n                    new Object[] { jobKey.getName(), jobKey.getGroup() },\n                    new String[] { String.class.getName(), String.class.getName() }));\n        } catch (ClassNotFoundException e) {\n            throw new SchedulerException(\"Unable to resolve job class\", e);\n        }\n    }\n\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws SchedulerException {\n            throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(JobKey jobKey) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(TriggerKey triggerKey) throws SchedulerException {\n        return (Boolean)invoke(\n                \"checkExists\", \n                new Object[] { triggerKey }, \n                new String[] { TriggerKey.class.getName() });\n    }\n    \n    public void clear() throws SchedulerException {\n        invoke(\n                \"clear\", \n                new Object[] {  }, \n                new String[] {  });\n    }\n\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public TriggerState getTriggerState(TriggerKey triggerKey)\n        throws SchedulerException {\n        return TriggerState.valueOf((String)invoke(\n                \"getTriggerState\",\n                new Object[] { triggerKey.getName(), triggerKey.getGroup() },\n                new String[] { String.class.getName(), String.class.getName() }));\n    }\n\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void resetTriggerFromErrorState(TriggerKey triggerKey)\n            throws SchedulerException {\n        invoke(\n            \"resetTriggerFromErrorState\",\n            new Object[] { triggerKey.getName(), triggerKey.getGroup() },\n            new String[] { String.class.getName(), String.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)\n        throws SchedulerException {\n        invoke(\n            \"addCalendar\", \n            new Object[] { calName, calendar, replace, updateTriggers },\n            new String[] { String.class.getName(), \n                    Calendar.class.getName(), boolean.class.getName(), boolean.class.getName() });\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public boolean deleteCalendar(String calName) throws SchedulerException {\n        invoke(\"deleteCalendar\",\n                new Object[] { calName },\n                new String[] { String.class.getName() });\n        return true;\n    }\n\n    /**\n     * <p>\n     * Calls th0e equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    public Calendar getCalendar(String calName) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>,\n     * passing the <code>SchedulingContext</code> associated with this\n     * instance.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getCalendarNames() throws SchedulerException {\n        return (List<String>)getAttribute(\"CalendarNames\");\n    }\n\n    /**\n     * @see org.quartz.Scheduler#getPausedTriggerGroups()\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> getPausedTriggerGroups() throws SchedulerException {\n        return (Set<String>)getAttribute(\"PausedTriggerGroups\");\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Other Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public ListenerManager getListenerManager() throws SchedulerException {\n        throw new SchedulerException(\n                \"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * @see org.quartz.Scheduler#interrupt(JobKey)\n     */\n    public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException  {\n        try {\n            return (Boolean)invoke(\n                    \"interruptJob\",\n                    new Object[] { jobKey.getName(), jobKey.getGroup() },\n                    new String[] { String.class.getName(), String.class.getName() });\n        } catch (SchedulerException se) {\n            throw new UnableToInterruptJobException(se);\n        }\n    }\n\n\n\n    public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException {\n        try {\n            return (Boolean)invoke(\n                    \"interruptJob\",\n                    new Object[] { fireInstanceId },\n                    new String[] { String.class.getName() });\n        } catch (SchedulerException se) {\n            throw new UnableToInterruptJobException(se);\n        }\n    }\n    \n    /**\n     * @see org.quartz.Scheduler#setJobFactory(org.quartz.spi.JobFactory)\n     */\n    public void setJobFactory(JobFactory factory) throws SchedulerException {\n        throw new SchedulerException(\"Operation not supported for remote schedulers.\");\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/RemoteScheduler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport java.rmi.RemoteException;\nimport java.rmi.registry.LocateRegistry;\nimport java.rmi.registry.Registry;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.ListenerManager;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.UnableToInterruptJobException;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.core.RemotableQuartzScheduler;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.JobFactory;\n\n/**\n * <p>\n * An implementation of the <code>Scheduler</code> interface that remotely\n * proxies all method calls to the equivalent call on a given <code>QuartzScheduler</code>\n * instance, via RMI.\n * </p>\n * \n * @see org.quartz.Scheduler\n * @see org.quartz.core.QuartzScheduler\n * \n * @author James House\n */\npublic class RemoteScheduler implements Scheduler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private RemotableQuartzScheduler rsched;\n\n    private final String schedId;\n\n    private final String rmiHost;\n\n    private final int rmiPort;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Construct a <code>RemoteScheduler</code> instance to proxy the given\n     * <code>RemotableQuartzScheduler</code> instance, and with the given\n     * <code>SchedulingContext</code>.\n     * </p>\n     */\n    public RemoteScheduler(String schedId, String host, int port) {\n        this.schedId = schedId;\n        this.rmiHost = host;\n        this.rmiPort = port;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected RemotableQuartzScheduler getRemoteScheduler()\n        throws SchedulerException {\n        if (rsched != null) {\n            return rsched;\n        }\n\n        try {\n            Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);\n\n            rsched = (RemotableQuartzScheduler) registry.lookup(schedId);\n\n        } catch (Exception e) {\n            throw new SchedulerException(\n                    \"Could not get handle to remote scheduler: \"\n                            + e.getMessage(), e);\n        }\n\n        return rsched;\n    }\n\n    protected SchedulerException invalidateHandleCreateException(String msg,\n            Exception cause) {\n        rsched = null;\n        return new SchedulerException(msg, cause);\n    }\n\n    /**\n     * <p>\n     * Returns the name of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerName() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getSchedulerName();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Returns the instance Id of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerInstanceId() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getSchedulerInstanceId();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    public SchedulerMetaData getMetaData() throws SchedulerException {\n        try {\n            RemotableQuartzScheduler sched = getRemoteScheduler();\n            return new SchedulerMetaData(getSchedulerName(),\n                    getSchedulerInstanceId(), getClass(), true, isStarted(), \n                    isInStandbyMode(), isShutdown(), sched.runningSince(), \n                    sched.numJobsExecuted(), sched.getJobStoreClass(), \n                    sched.supportsPersistence(), sched.isClustered(), sched.getThreadPoolClass(), \n                    sched.getThreadPoolSize(), sched.getVersion());\n\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.\n     * </p>\n     */\n    public SchedulerContext getContext() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getSchedulerContext();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduler State Management Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void start() throws SchedulerException {\n        try {\n            getRemoteScheduler().start();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void startDelayed(int seconds) throws SchedulerException {\n        try {\n            getRemoteScheduler().startDelayed(seconds);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void standby() throws SchedulerException {\n        try {\n            getRemoteScheduler().standby();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * Whether the scheduler has been started.  \n     * \n     * <p>\n     * Note: This only reflects whether <code>{@link #start()}</code> has ever\n     * been called on this Scheduler, so it will return <code>true</code> even \n     * if the <code>Scheduler</code> is currently in standby mode or has been \n     * since shutdown.\n     * </p>\n     * \n     * @see #start()\n     * @see #isShutdown()\n     * @see #isInStandbyMode()\n     */    \n    public boolean isStarted() throws SchedulerException {\n        try {\n            return (getRemoteScheduler().runningSince() != null);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }   \n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isInStandbyMode() throws SchedulerException {\n        try {\n            return getRemoteScheduler().isInStandbyMode();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown() throws SchedulerException {\n        try {\n            String schedulerName = getSchedulerName();\n            \n            getRemoteScheduler().shutdown();\n            \n            SchedulerRepository.getInstance().remove(schedulerName);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown(boolean waitForJobsToComplete)\n        throws SchedulerException {\n        try {\n            String schedulerName = getSchedulerName();\n            \n            getRemoteScheduler().shutdown(waitForJobsToComplete);\n\n            SchedulerRepository.getInstance().remove(schedulerName);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isShutdown() throws SchedulerException {\n        try {\n            return getRemoteScheduler().isShutdown();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getCurrentlyExecutingJobs();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduling-related Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date scheduleJob(JobDetail jobDetail, Trigger trigger)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().scheduleJob(jobDetail,\n                    trigger);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date scheduleJob(Trigger trigger) throws SchedulerException {\n        try {\n            return getRemoteScheduler().scheduleJob(trigger);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void addJob(JobDetail jobDetail, boolean replace)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().addJob(jobDetail, replace);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)\n            throws SchedulerException {\n        try {\n            getRemoteScheduler().addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    public boolean deleteJobs(List<JobKey> jobKeys) throws SchedulerException {\n        try {\n            return getRemoteScheduler().deleteJobs(jobKeys);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    public void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException {\n            try {\n                getRemoteScheduler().scheduleJobs(triggersAndJobs, replace);\n            } catch (RemoteException re) {\n                throw invalidateHandleCreateException(\n                        \"Error communicating with remote scheduler.\", re);\n            }\n    }\n    \n    public void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException {\n        try {\n            getRemoteScheduler().scheduleJob(jobDetail, triggersForJob, replace);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    public boolean unscheduleJobs(List<TriggerKey> triggerKeys)\n            throws SchedulerException {\n        try {\n            return getRemoteScheduler().unscheduleJobs(triggerKeys);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean deleteJob(JobKey jobKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler()\n                    .deleteJob(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean unscheduleJob(TriggerKey triggerKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().unscheduleJob(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date rescheduleJob(TriggerKey triggerKey,\n            Trigger newTrigger) throws SchedulerException {\n        try {\n            return getRemoteScheduler().rescheduleJob(triggerKey,\n                    newTrigger);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n    \n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey)\n        throws SchedulerException {\n        triggerJob(jobKey, null);\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey, JobDataMap data)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().triggerJob(jobKey, data);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler()\n                    .pauseTrigger(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        try {\n            getRemoteScheduler().pauseTriggers(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseJob(JobKey jobKey)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().pauseJob(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        try {\n            getRemoteScheduler().pauseJobs(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().resumeTrigger(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        try {\n            getRemoteScheduler().resumeTriggers(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeJob(JobKey jobKey)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().resumeJob(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        try {\n            getRemoteScheduler().resumeJobs(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseAll() throws SchedulerException {\n        try {\n            getRemoteScheduler().pauseAll();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeAll() throws SchedulerException {\n        try {\n            getRemoteScheduler().resumeAll();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getJobGroupNames() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getJobGroupNames();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        try {\n            return getRemoteScheduler().getJobKeys(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<? extends Trigger> getTriggersOfJob(JobKey jobKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().getTriggersOfJob(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getTriggerGroupNames() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getTriggerGroupNames();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        try {\n            return getRemoteScheduler().getTriggerKeys(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public JobDetail getJobDetail(JobKey jobKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().getJobDetail(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().getJobDetails(matcher);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(JobKey jobKey) throws SchedulerException {\n        try {\n            return getRemoteScheduler().checkExists(jobKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n   \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(TriggerKey triggerKey) throws SchedulerException {\n        try {\n            return getRemoteScheduler().checkExists(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n  \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void clear() throws SchedulerException {\n        try {\n            getRemoteScheduler().clear();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Trigger getTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().getTrigger(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public TriggerState getTriggerState(TriggerKey triggerKey)\n        throws SchedulerException {\n        try {\n            return getRemoteScheduler().getTriggerState(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resetTriggerFromErrorState(TriggerKey triggerKey)\n            throws SchedulerException {\n        try {\n            getRemoteScheduler().resetTriggerFromErrorState(triggerKey);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n\n\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)\n        throws SchedulerException {\n        try {\n            getRemoteScheduler().addCalendar(calName, calendar,\n                    replace, updateTriggers);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean deleteCalendar(String calName) throws SchedulerException {\n        try {\n            return getRemoteScheduler().deleteCalendar(calName);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Calendar getCalendar(String calName) throws SchedulerException {\n        try {\n            return getRemoteScheduler().getCalendar(calName);\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getCalendarNames() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getCalendarNames();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n    /** \n     * @see org.quartz.Scheduler#getPausedTriggerGroups()\n     */\n    public Set<String> getPausedTriggerGroups() throws SchedulerException {\n        try {\n            return getRemoteScheduler().getPausedTriggerGroups();\n        } catch (RemoteException re) {\n            throw invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re);\n        }\n    }\n\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Other Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n\n    public ListenerManager getListenerManager() throws SchedulerException {\n        throw new SchedulerException(\n            \"Operation not supported for remote schedulers.\");\n    }\n\n    /**\n     * @see org.quartz.Scheduler#interrupt(JobKey)\n     */\n    public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException  {\n        try {\n            return getRemoteScheduler().interrupt(jobKey);\n        } catch (RemoteException re) {\n            throw new UnableToInterruptJobException(invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re));\n        } catch (SchedulerException se) {\n            throw new UnableToInterruptJobException(se);\n        }\n    }\n\n    public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException {\n        try {\n            return getRemoteScheduler().interrupt(fireInstanceId);\n        } catch (RemoteException re) {\n            throw new UnableToInterruptJobException(invalidateHandleCreateException(\n                    \"Error communicating with remote scheduler.\", re));\n        } catch (SchedulerException se) {\n            throw new UnableToInterruptJobException(se);\n        }\n    }\n\n    /**\n     * @see org.quartz.Scheduler#setJobFactory(org.quartz.spi.JobFactory)\n     */\n    public void setJobFactory(JobFactory factory) throws SchedulerException {\n        throw new SchedulerException(\n                \"Operation not supported for remote schedulers.\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/SchedulerDetailsSetter.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.SchedulerException;\n\n/**\n * This utility calls methods reflectively on the given objects even though the\n * methods are likely on a proper interface (ThreadPool, JobStore, etc). The\n * motivation is to be tolerant of older implementations that have not been\n * updated for the changes in the interfaces (eg. LocalTaskExecutorThreadPool in\n * spring quartz helpers)\n *\n * @author teck\n */\nclass SchedulerDetailsSetter {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerDetailsSetter.class);\n\n    private SchedulerDetailsSetter() {\n        //\n    }\n\n    static void setDetails(Object target, String schedulerName,\n            String schedulerId) throws SchedulerException {\n        set(target, \"setInstanceName\", schedulerName);\n        set(target, \"setInstanceId\", schedulerId);\n    }\n\n    private static void set(Object target, String method, String value)\n            throws SchedulerException {\n        final Method setter;\n\n        try {\n            setter = target.getClass().getMethod(method, String.class);\n        } catch (SecurityException e) {\n            LOGGER.error(\"A SecurityException occurred: {}\", e.getMessage(), e);\n            return;\n        } catch (NoSuchMethodException e) {\n            // This probably won't happen since the interface has the method\n            LOGGER.warn(\"{} does not contain public method {}(String)\", target.getClass().getName(), method);\n            return;\n        }\n\n        if (Modifier.isAbstract(setter.getModifiers())) {\n            // expected if method not implemented (but is present on\n            // interface)\n            LOGGER.warn(\"{} does not implement {}(String)\", target.getClass().getName(), method);\n            return;\n        }\n\n        try {\n            setter.invoke(target, value);\n        } catch (InvocationTargetException ite) {\n            throw new SchedulerException(ite.getTargetException());\n        } catch (Exception e) {\n            throw new SchedulerException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/SchedulerRepository.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport java.util.Collection;\nimport java.util.HashMap;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\n/**\n * <p>\n * Holds references to Scheduler instances - ensuring uniqueness, and\n * preventing garbage collection, and allowing 'global' lookups - all within a\n * ClassLoader space.\n * </p>\n * \n * @author James House\n */\npublic class SchedulerRepository {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final HashMap<String, Scheduler> schedulers;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private SchedulerRepository() {\n        schedulers = new HashMap<>();\n    }\n\n    private static class Holder {\n        private static final SchedulerRepository INSTANCE = new SchedulerRepository();\n    }\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static synchronized SchedulerRepository getInstance() {\n        return Holder.INSTANCE;\n    }\n\n    public synchronized void bind(Scheduler sched) throws SchedulerException {\n\n        if (schedulers.get(sched.getSchedulerName()) != null) {\n            throw new SchedulerException(\"Scheduler with name '\"\n                    + sched.getSchedulerName() + \"' already exists.\");\n        }\n\n        schedulers.put(sched.getSchedulerName(), sched);\n    }\n\n    public synchronized boolean remove(String schedName) {\n        return (schedulers.remove(schedName) != null);\n    }\n\n    public synchronized Scheduler lookup(String schedName) {\n        return schedulers.get(schedName);\n    }\n\n    public synchronized Collection<Scheduler> lookupAll() {\n        return java.util.Collections\n                .unmodifiableCollection(schedulers.values());\n    }\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/StdJobRunShellFactory.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.core.JobRunShell;\nimport org.quartz.core.JobRunShellFactory;\nimport org.quartz.spi.TriggerFiredBundle;\n\n/**\n * <p>\n * Responsible for creating the instances of <code>{@link org.quartz.core.JobRunShell}</code>\n * to be used within the <code>{@link org.quartz.core.QuartzScheduler}</code> instance.\n * </p>\n * \n * @author James House\n */\npublic class StdJobRunShellFactory implements JobRunShellFactory {\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Scheduler scheduler;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Initialize the factory, providing a handle to the <code>Scheduler</code>\n     * that should be made available within the <code>JobRunShell</code> and\n     * the <code>JobExecutionContext</code> s within it.\n     * </p>\n     */\n    public void initialize(Scheduler sched) {\n        this.scheduler = sched;\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>\n     * to obtain instances of <code>{@link org.quartz.core.JobRunShell}</code>.\n     * </p>\n     */\n    public JobRunShell createJobRunShell(TriggerFiredBundle bundle) throws SchedulerException {\n        return new JobRunShell(scheduler, bundle);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/StdScheduler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.ListenerManager;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.UnableToInterruptJobException;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.core.QuartzScheduler;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.JobFactory;\n\n/**\n * <p>\n * An implementation of the <code>Scheduler</code> interface that directly\n * proxies all method calls to the equivalent call on a given <code>QuartzScheduler</code>\n * instance.\n * </p>\n * \n * @see org.quartz.Scheduler\n * @see org.quartz.core.QuartzScheduler\n *\n * @author James House\n */\npublic class StdScheduler implements Scheduler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final QuartzScheduler sched;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Construct a <code>StdScheduler</code> instance to proxy the given\n     * <code>QuartzScheduler</code> instance, and with the given <code>SchedulingContext</code>.\n     * </p>\n     */\n    public StdScheduler(QuartzScheduler sched) {\n        this.sched = sched;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Returns the name of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerName() {\n        return sched.getSchedulerName();\n    }\n\n    /**\n     * <p>\n     * Returns the instance Id of the <code>Scheduler</code>.\n     * </p>\n     */\n    public String getSchedulerInstanceId() {\n        return sched.getSchedulerInstanceId();\n    }\n\n    public SchedulerMetaData getMetaData() {\n        return new SchedulerMetaData(getSchedulerName(),\n                getSchedulerInstanceId(), getClass(), false, isStarted(), \n                isInStandbyMode(), isShutdown(), sched.runningSince(), \n                sched.numJobsExecuted(), sched.getJobStoreClass(), \n                sched.supportsPersistence(), sched.isClustered(), sched.getThreadPoolClass(), \n                sched.getThreadPoolSize(), sched.getVersion());\n\n    }\n\n    /**\n     * <p>\n     * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.\n     * </p>\n     */\n    public SchedulerContext getContext() throws SchedulerException {\n        return sched.getSchedulerContext();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduler State Management Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void start() throws SchedulerException {\n        sched.start();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void startDelayed(int seconds) throws SchedulerException {\n        sched.startDelayed(seconds);\n    }\n\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void standby() {\n        sched.standby();\n    }\n    \n    /**\n     * Whether the scheduler has been started.  \n     * \n     * <p>\n     * Note: This only reflects whether <code>{@link #start()}</code> has ever\n     * been called on this Scheduler, so it will return <code>true</code> even \n     * if the <code>Scheduler</code> is currently in standby mode or has been \n     * since shutdown.\n     * </p>\n     * \n     * @see #start()\n     * @see #isShutdown()\n     * @see #isInStandbyMode()\n     */    \n    public boolean isStarted() {\n        return (sched.runningSince() != null);\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isInStandbyMode() {\n        return sched.isInStandbyMode();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown() {\n        sched.shutdown();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void shutdown(boolean waitForJobsToComplete) {\n        sched.shutdown(waitForJobsToComplete);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean isShutdown() {\n        return sched.isShutdown();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<JobExecutionContext> getCurrentlyExecutingJobs() {\n        return sched.getCurrentlyExecutingJobs();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Scheduling-related Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void clear() throws SchedulerException {\n        sched.clear();\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date scheduleJob(JobDetail jobDetail, Trigger trigger)\n        throws SchedulerException {\n        return sched.scheduleJob(jobDetail, trigger);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date scheduleJob(Trigger trigger) throws SchedulerException {\n        return sched.scheduleJob(trigger);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void addJob(JobDetail jobDetail, boolean replace)\n        throws SchedulerException {\n        sched.addJob(jobDetail, replace);\n    }\n\n    public void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)\n            throws SchedulerException {\n        sched.addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling);\n    }\n\n\n    public boolean deleteJobs(List<JobKey> jobKeys) throws SchedulerException {\n        return sched.deleteJobs(jobKeys);\n    }\n\n    public void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException {\n        sched.scheduleJobs(triggersAndJobs, replace);\n    }\n\n    public void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException {\n        sched.scheduleJob(jobDetail,  triggersForJob, replace);\n    }\n    \n    public boolean unscheduleJobs(List<TriggerKey> triggerKeys)\n            throws SchedulerException {\n        return sched.unscheduleJobs(triggerKeys);\n    }    \n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean deleteJob(JobKey jobKey)\n        throws SchedulerException {\n        return sched.deleteJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean unscheduleJob(TriggerKey triggerKey)\n        throws SchedulerException {\n        return sched.unscheduleJob(triggerKey);\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Date rescheduleJob(TriggerKey triggerKey,\n            Trigger newTrigger) throws SchedulerException {\n        return sched.rescheduleJob(triggerKey, newTrigger);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey)\n        throws SchedulerException {\n        triggerJob(jobKey, null);\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void triggerJob(JobKey jobKey, JobDataMap data)\n        throws SchedulerException {\n        sched.triggerJob(jobKey, data);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        sched.pauseTrigger(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        sched.pauseTriggers(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseJob(JobKey jobKey)\n        throws SchedulerException {\n        sched.pauseJob(jobKey);\n    }\n\n    /** \n     * @see org.quartz.Scheduler#getPausedTriggerGroups()\n     */\n    public Set<String> getPausedTriggerGroups() throws SchedulerException {\n        return sched.getPausedTriggerGroups();\n    }\n    \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        sched.pauseJobs(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        sched.resumeTrigger(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        sched.resumeTriggers(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeJob(JobKey jobKey)\n        throws SchedulerException {\n        sched.resumeJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        sched.resumeJobs(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void pauseAll() throws SchedulerException {\n        sched.pauseAll();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void resumeAll() throws SchedulerException {\n        sched.resumeAll();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getJobGroupNames() throws SchedulerException {\n        return sched.getJobGroupNames();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<? extends Trigger> getTriggersOfJob(JobKey jobKey)\n        throws SchedulerException {\n        return sched.getTriggersOfJob(jobKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException {\n        return sched.getJobKeys(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getTriggerGroupNames() throws SchedulerException {\n        return sched.getTriggerGroupNames();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException {\n        return sched.getTriggerKeys(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public JobDetail getJobDetail(JobKey jobKey)\n        throws SchedulerException {\n        return sched.getJobDetail(jobKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws SchedulerException {\n        return sched.getJobDetails(matcher);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Trigger getTrigger(TriggerKey triggerKey)\n        throws SchedulerException {\n        return sched.getTrigger(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public TriggerState getTriggerState(TriggerKey triggerKey)\n        throws SchedulerException {\n        return sched.getTriggerState(triggerKey);\n    }\n\n    /**\n     * Reset the current state of the identified <code>{@link Trigger}</code>\n     * from {@link TriggerState#ERROR} to {@link TriggerState#NORMAL} or\n     * {@link TriggerState#PAUSED} as appropriate.\n     *\n     * <p>Only affects triggers that are in ERROR state - if identified trigger is not\n     * in that state then the result is a no-op.</p>\n     *\n     * <p>The result will be the trigger returning to the normal, waiting to\n     * be fired state, unless the trigger's group has been paused, in which\n     * case it will go into the PAUSED state.</p>\n     *\n     * @see Trigger.TriggerState\n     */\n    public void resetTriggerFromErrorState(TriggerKey triggerKey)\n            throws SchedulerException {\n        sched.resetTriggerFromErrorState(triggerKey);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)\n        throws SchedulerException {\n        sched.addCalendar(calName, calendar, replace, updateTriggers);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean deleteCalendar(String calName) throws SchedulerException {\n        return sched.deleteCalendar(calName);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public Calendar getCalendar(String calName) throws SchedulerException {\n        return sched.getCalendar(calName);\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public List<String> getCalendarNames() throws SchedulerException {\n        return sched.getCalendarNames();\n    }\n\n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(JobKey jobKey) throws SchedulerException {\n        return sched.checkExists(jobKey);\n    }\n    \n   \n    /**\n     * <p>\n     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.\n     * </p>\n     */\n    public boolean checkExists(TriggerKey triggerKey) throws SchedulerException {\n        return sched.checkExists(triggerKey);\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    ///\n    /// Other Methods\n    ///\n    ///////////////////////////////////////////////////////////////////////////\n\n    \n\n    /**\n     * @see org.quartz.Scheduler#setJobFactory(org.quartz.spi.JobFactory)\n     */\n    public void setJobFactory(JobFactory factory) throws SchedulerException {\n        sched.setJobFactory(factory);\n    }\n\n    /**\n     * @see org.quartz.Scheduler#getListenerManager()\n     */\n    public ListenerManager getListenerManager() throws SchedulerException {\n        return sched.getListenerManager();\n    }\n\n    public boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException {\n        return sched.interrupt(jobKey);\n    }\n\n    public boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException {\n        return sched.interrupt(fireInstanceId);\n    }\n\n  \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/StdSchedulerFactory.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.impl;\n\nimport org.quartz.JobListener;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.TriggerListener;\nimport org.quartz.core.JobRunShellFactory;\nimport org.quartz.core.QuartzScheduler;\nimport org.quartz.core.QuartzSchedulerResources;\nimport org.quartz.ee.jta.JTAAnnotationAwareJobRunShellFactory;\nimport org.quartz.ee.jta.JTAJobRunShellFactory;\nimport org.quartz.ee.jta.UserTransactionHelper;\nimport org.quartz.impl.jdbcjobstore.JobStoreSupport;\nimport org.quartz.impl.jdbcjobstore.Semaphore;\nimport org.quartz.impl.jdbcjobstore.TablePrefixAware;\nimport org.quartz.impl.matchers.EverythingMatcher;\nimport org.quartz.management.ManagementRESTServiceConfiguration;\nimport org.quartz.simpl.RAMJobStore;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.InstanceIdGenerator;\nimport org.quartz.spi.JobFactory;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.quartz.spi.ThreadExecutor;\nimport org.quartz.spi.ThreadPool;\nimport org.quartz.utils.ConnectionProvider;\nimport org.quartz.utils.DBConnectionManager;\nimport org.quartz.utils.JNDIConnectionProvider;\nimport org.quartz.utils.C3p0PoolingConnectionProvider;\nimport org.quartz.utils.PoolingConnectionProvider;\nimport org.quartz.utils.PropertiesParser;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.PropertyDescriptor;\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.security.AccessControlException;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.Locale;\nimport java.util.Properties;\n\n/**\n * <p>\n * An implementation of <code>{@link org.quartz.SchedulerFactory}</code> that\n * does all of its work of creating a <code>QuartzScheduler</code> instance\n * based on the contents of a <code>Properties</code> file.\n * </p>\n *\n * <p>\n * By default a properties file named \"quartz.properties\" is loaded from the\n * 'current working directory'. If that fails, then the \"quartz.properties\"\n * file located (as a resource) in the org/quartz package is loaded. If you\n * wish to use a file other than these defaults, you must define the system\n * property 'org.quartz.properties' to point to the file you want.\n * </p>\n *\n * <p>\n * Alternatively, you can explicitly initialize the factory by calling one of\n * the <code>initialize(xx)</code> methods before calling <code>getScheduler()</code>.\n * </p>\n *\n * <p>\n * See the sample properties files that are distributed with Quartz for\n * information about the various settings available within the file.\n * Full configuration documentation can be found at\n * http://www.quartz-scheduler.org/docs/index.html\n * </p>\n *\n * <p>\n * Instances of the specified <code>{@link org.quartz.spi.JobStore}</code>,\n * <code>{@link org.quartz.spi.ThreadPool}</code>, and other SPI classes will be created\n * by name, and then any additional properties specified for them in the config\n * file will be set on the instance by calling an equivalent 'set' method. For\n * example if the properties file contains the property\n * 'org.quartz.jobStore.myProp = 10' then after the JobStore class has been\n * instantiated, the method 'setMyProp()' will be called on it. Type conversion\n * to primitive Java types (int, long, float, double, boolean, and String) are\n * performed before calling the property's setter method.\n * </p>\n * \n * <p>\n * One property can reference another property's value by specifying a value\n * following the convention of \"$@other.property.name\", for example, to reference\n * the scheduler's instance name as the value for some other property, you\n * would use \"$@org.quartz.scheduler.instanceName\".\n * </p> \n *\n * @author James House\n * @author Anthony Eden\n * @author Mohammad Rezaei\n */\npublic class StdSchedulerFactory implements SchedulerFactory {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constants.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String PROPERTIES_FILE = \"org.quartz.properties\";\n\n    public static final String PROP_SCHED_INSTANCE_NAME = \"org.quartz.scheduler.instanceName\";\n\n    public static final String PROP_SCHED_INSTANCE_ID = \"org.quartz.scheduler.instanceId\";\n\n    public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX = \"org.quartz.scheduler.instanceIdGenerator\";\n\n    public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS =\n        PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX + \".class\";\n\n    public static final String PROP_SCHED_THREAD_NAME = \"org.quartz.scheduler.threadName\";\n\n    public static final String PROP_SCHED_BATCH_TIME_WINDOW = \"org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow\";\n\n    public static final String PROP_SCHED_MAX_BATCH_SIZE = \"org.quartz.scheduler.batchTriggerAcquisitionMaxCount\";\n\n    public static final String PROP_SCHED_JMX_EXPORT = \"org.quartz.scheduler.jmx.export\";\n\n    public static final String PROP_SCHED_JMX_OBJECT_NAME = \"org.quartz.scheduler.jmx.objectName\";\n\n    public static final String PROP_SCHED_JMX_PROXY = \"org.quartz.scheduler.jmx.proxy\";\n\n    public static final String PROP_SCHED_JMX_PROXY_CLASS = \"org.quartz.scheduler.jmx.proxy.class\";\n    \n    public static final String PROP_SCHED_RMI_EXPORT = \"org.quartz.scheduler.rmi.export\";\n\n    public static final String PROP_SCHED_RMI_PROXY = \"org.quartz.scheduler.rmi.proxy\";\n\n    public static final String PROP_SCHED_RMI_HOST = \"org.quartz.scheduler.rmi.registryHost\";\n\n    public static final String PROP_SCHED_RMI_PORT = \"org.quartz.scheduler.rmi.registryPort\";\n\n    public static final String PROP_SCHED_RMI_SERVER_PORT = \"org.quartz.scheduler.rmi.serverPort\";\n\n    public static final String PROP_SCHED_RMI_CREATE_REGISTRY = \"org.quartz.scheduler.rmi.createRegistry\";\n\n    public static final String PROP_SCHED_RMI_BIND_NAME = \"org.quartz.scheduler.rmi.bindName\";\n\n    public static final String PROP_SCHED_WRAP_JOB_IN_USER_TX = \"org.quartz.scheduler.wrapJobExecutionInUserTransaction\";\n\n    public static final String PROP_SCHED_USER_TX_URL = \"org.quartz.scheduler.userTransactionURL\";\n\n    public static final String PROP_SCHED_IDLE_WAIT_TIME = \"org.quartz.scheduler.idleWaitTime\";\n\n    public static final String PROP_SCHED_DB_FAILURE_RETRY_INTERVAL = \"org.quartz.scheduler.dbFailureRetryInterval\";\n\n    public static final String PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON = \"org.quartz.scheduler.makeSchedulerThreadDaemon\";\n\n    public static final String PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD = \"org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer\";\n\n    public static final String PROP_SCHED_CLASS_LOAD_HELPER_CLASS = \"org.quartz.scheduler.classLoadHelper.class\";\n\n    public static final String PROP_SCHED_JOB_FACTORY_CLASS = \"org.quartz.scheduler.jobFactory.class\";\n\n    public static final String PROP_SCHED_JOB_FACTORY_PREFIX = \"org.quartz.scheduler.jobFactory\";\n\n    public static final String PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN = \"org.quartz.scheduler.interruptJobsOnShutdown\";\n\n    public static final String PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT = \"org.quartz.scheduler.interruptJobsOnShutdownWithWait\";\n\n    public static final String PROP_SCHED_CONTEXT_PREFIX = \"org.quartz.context.key\";\n\n    public static final String PROP_THREAD_POOL_PREFIX = \"org.quartz.threadPool\";\n\n    public static final String PROP_THREAD_POOL_CLASS = \"org.quartz.threadPool.class\";\n\n    public static final String PROP_JOB_STORE_PREFIX = \"org.quartz.jobStore\";\n\n    public static final String PROP_JOB_STORE_LOCK_HANDLER_PREFIX = PROP_JOB_STORE_PREFIX + \".lockHandler\";\n\n    public static final String PROP_JOB_STORE_LOCK_HANDLER_CLASS = PROP_JOB_STORE_LOCK_HANDLER_PREFIX + \".class\";\n\n    public static final String PROP_TABLE_PREFIX = \"tablePrefix\";\n\n    public static final String PROP_SCHED_NAME = \"schedName\";\n\n    public static final String PROP_JOB_STORE_CLASS = \"org.quartz.jobStore.class\";\n\n    public static final String PROP_JOB_STORE_USE_PROP = \"org.quartz.jobStore.useProperties\";\n\n    public static final String PROP_DATASOURCE_PREFIX = \"org.quartz.dataSource\";\n\n    public static final String PROP_CONNECTION_PROVIDER_CLASS = \"connectionProvider.class\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_DRIVER}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_DRIVER = \"driver\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_URL}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_URL = \"URL\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_USER}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_USER = \"user\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_PASSWORD}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_PASSWORD = \"password\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_MAX_CONNECTIONS}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_MAX_CONNECTIONS = \"maxConnections\";\n\n    /**\n     * @deprecated Replaced with {@link PoolingConnectionProvider#DB_VALIDATION_QUERY}\n     */\n    @Deprecated\n    public static final String PROP_DATASOURCE_VALIDATION_QUERY = \"validationQuery\";\n\n    public static final String PROP_DATASOURCE_JNDI_URL = \"jndiURL\";\n\n    public static final String PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP = \"jndiAlwaysLookup\";\n\n    public static final String PROP_DATASOURCE_JNDI_INITIAL = \"java.naming.factory.initial\";\n\n    public static final String PROP_DATASOURCE_JNDI_PROVIDER = \"java.naming.provider.url\";\n\n    public static final String PROP_DATASOURCE_JNDI_PRINCIPAL = \"java.naming.security.principal\";\n\n    public static final String PROP_DATASOURCE_JNDI_CREDENTIALS = \"java.naming.security.credentials\";\n\n    public static final String PROP_PLUGIN_PREFIX = \"org.quartz.plugin\";\n\n    public static final String PROP_PLUGIN_CLASS = \"class\";\n\n    public static final String PROP_JOB_LISTENER_PREFIX = \"org.quartz.jobListener\";\n\n    public static final String PROP_TRIGGER_LISTENER_PREFIX = \"org.quartz.triggerListener\";\n\n    public static final String PROP_LISTENER_CLASS = \"class\";\n\n    public static final String DEFAULT_INSTANCE_ID = \"NON_CLUSTERED\";\n\n    public static final String AUTO_GENERATE_INSTANCE_ID = \"AUTO\";\n\n    public static final String PROP_THREAD_EXECUTOR = \"org.quartz.threadExecutor\";\n\n    public static final String PROP_THREAD_EXECUTOR_CLASS = \"org.quartz.threadExecutor.class\";\n\n    public static final String SYSTEM_PROPERTY_AS_INSTANCE_ID = \"SYS_PROP\";\n    \n    public static final String MANAGEMENT_REST_SERVICE_ENABLED = \"org.quartz.managementRESTService.enabled\";\n\n    public static final String MANAGEMENT_REST_SERVICE_HOST_PORT = \"org.quartz.managementRESTService.bind\";\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private SchedulerException initException = null;\n\n    private String propSrc = null;\n\n    private PropertiesParser cfg;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    //  private Scheduler scheduler;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Create an uninitialized StdSchedulerFactory.\n     */\n    public StdSchedulerFactory() {\n    }\n\n    /**\n     * Create a StdSchedulerFactory that has been initialized via\n     * <code>{@link #initialize(Properties)}</code>.\n     *\n     * @see #initialize(Properties)\n     */\n    public StdSchedulerFactory(Properties props) throws SchedulerException {\n        initialize(props);\n    }\n\n    /**\n     * Create a StdSchedulerFactory that has been initialized via\n     * <code>{@link #initialize(String)}</code>.\n     *\n     * @see #initialize(String)\n     */\n    public StdSchedulerFactory(String fileName) throws SchedulerException {\n        initialize(fileName);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public Logger getLog() {\n        return log;\n    }\n\n    /**\n     * <p>\n     * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with\n     * the contents of a <code>Properties</code> file and overriding System\n     * properties.\n     * </p>\n     *\n     * <p>\n     * By default a properties file named \"quartz.properties\" is loaded from\n     * the 'current working directory'. If that fails, then the\n     * \"quartz.properties\" file located (as a resource) in the org/quartz\n     * package is loaded. If you wish to use a file other than these defaults,\n     * you must define the system property 'org.quartz.properties' to point to\n     * the file you want.\n     * </p>\n     *\n     * <p>\n     * System properties (environment variables, and -D definitions on the\n     * command-line when running the JVM) override any properties in the\n     * loaded file.  For this reason, you may want to use a different initialize()\n     * method if your application security policy prohibits access to\n     * <code>{@link java.lang.System#getProperties()}</code>.\n     * </p>\n     */\n    public void initialize() throws SchedulerException {\n        // short-circuit if already initialized\n        if (cfg != null) {\n            return;\n        }\n        if (initException != null) {\n            throw initException;\n        }\n\n        String requestedFile = System.getProperty(PROPERTIES_FILE);\n        String propFileName = requestedFile != null ? requestedFile\n                : \"quartz.properties\";\n        File propFile = new File(propFileName);\n\n        Properties props = new Properties();\n\n        InputStream in = null;\n\n        try {\n            if (propFile.exists()) {\n                try {\n                    if (requestedFile != null) {\n                        propSrc = \"specified file: '\" + requestedFile + \"'\";\n                    } else {\n                        propSrc = \"default file in current working dir: 'quartz.properties'\";\n                    }\n\n                    in = new BufferedInputStream(new FileInputStream(propFileName));\n                    props.load(in);\n\n                } catch (IOException ioe) {\n                    initException = new SchedulerException(\"Properties file: '\"\n                            + propFileName + \"' could not be read.\", ioe);\n                    throw initException;\n                }\n            } else if (requestedFile != null) {\n                in =\n                    Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile);\n\n                if(in == null) {\n                    initException = new SchedulerException(\"Properties file: '\"\n                        + requestedFile + \"' could not be found.\");\n                    throw initException;\n                }\n\n                propSrc = \"specified file: '\" + requestedFile + \"' in the class resource path.\";\n\n                in = new BufferedInputStream(in);\n                try {\n                    props.load(in);\n                } catch (IOException ioe) {\n                    initException = new SchedulerException(\"Properties file: '\"\n                            + requestedFile + \"' could not be read.\", ioe);\n                    throw initException;\n                }\n\n            } else {\n                propSrc = \"default resource file in Quartz package: 'quartz.properties'\";\n\n                ClassLoader cl = getClass().getClassLoader();\n                if(cl == null)\n                    cl = findClassLoader();\n                if(cl == null)\n                    throw new SchedulerConfigException(\"Unable to find a class loader on the current thread or class.\");\n\n                in = cl.getResourceAsStream(\n                        \"quartz.properties\");\n\n                if (in == null) {\n                    in = cl.getResourceAsStream(\n                            \"/quartz.properties\");\n                }\n                if (in == null) {\n                    in = cl.getResourceAsStream(\n                            \"org/quartz/quartz.properties\");\n                }\n                if (in == null) {\n                    initException = new SchedulerException(\n                            \"Default quartz.properties not found in class path\");\n                    throw initException;\n                }\n                try {\n                    props.load(in);\n                } catch (IOException ioe) {\n                    initException = new SchedulerException(\n                            \"Resource properties file: 'org/quartz/quartz.properties' \"\n                                    + \"could not be read from the classpath.\", ioe);\n                    throw initException;\n                }\n            }\n        } finally {\n            if(in != null) {\n                try { in.close(); } catch(IOException ignore) { /* ignore */ }\n            }\n        }\n\n        initialize(overrideWithSysProps(props, getLog()));\n    }\n\n    /**\n     * Add all System properties to the given <code>props</code>.  Will override\n     * any properties that already exist in the given <code>props</code>.\n     */\n    // Visible for testing\n    static Properties overrideWithSysProps(Properties props, Logger log) {\n        Properties sysProps = null;\n        try {\n            sysProps = System.getProperties();\n        } catch (AccessControlException e) {\n            log.warn(\n                \"Skipping overriding quartz properties with System properties \" +\n                \"during initialization because of an AccessControlException.  \" +\n                \"This is likely due to not having read/write access for \" +\n                \"java.util.PropertyPermission as required by java.lang.System.getProperties().  \" +\n                \"To resolve this warning, either add this permission to your policy file or \" +\n                \"use a non-default version of initialize().\",\n                e);\n        }\n\n        if (sysProps != null) {\n            // Use the propertyNames to iterate to avoid \n            // a possible ConcurrentModificationException\n            Enumeration<?> en = sysProps.propertyNames();\n            while (en.hasMoreElements()) {\n                Object name = en.nextElement();\n                Object value = sysProps.get(name);\n                if (name instanceof String && value instanceof String) {\n                    // Properties javadoc discourages use of put so we use setProperty\n                    props.setProperty((String) name, (String) value);\n                }\n            }\n        }\n\n        return props;\n    }\n\n    /**\n     * <p>\n     * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with\n     * the contents of the <code>Properties</code> file with the given\n     * name.\n     * </p>\n     */\n    public void initialize(String filename) throws SchedulerException {\n        // short-circuit if already initialized\n        if (cfg != null) {\n            return;\n        }\n\n        if (initException != null) {\n            throw initException;\n        }\n\n        InputStream is;\n        Properties props = new Properties();\n\n        is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);\n\n        try {\n            if(is != null) {\n                is = new BufferedInputStream(is);\n                propSrc = \"the specified file : '\" + filename + \"' from the class resource path.\";\n            } else {\n                is = new BufferedInputStream(new FileInputStream(filename));\n                propSrc = \"the specified file : '\" + filename + \"'\";\n            }\n            props.load(is);\n        } catch (IOException ioe) {\n            initException = new SchedulerException(\"Properties file: '\"\n                    + filename + \"' could not be read.\", ioe);\n            throw initException;\n        }\n        finally {\n            if(is != null)\n                try { is.close(); } catch(IOException ignore) {}\n        }\n\n        initialize(props);\n    }\n\n    /**\n     * <p>\n     * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with\n     * the contents of the <code>Properties</code> file opened with the\n     * given <code>InputStream</code>.\n     * </p>\n     */\n    public void initialize(InputStream propertiesStream)\n        throws SchedulerException {\n        // short-circuit if already initialized\n        if (cfg != null) {\n            return;\n        }\n\n        if (initException != null) {\n            throw initException;\n        }\n\n        Properties props = new Properties();\n\n        if (propertiesStream != null) {\n            try {\n                props.load(propertiesStream);\n                propSrc = \"an externally opened InputStream.\";\n            } catch (IOException e) {\n                initException = new SchedulerException(\n                        \"Error loading property data from InputStream\", e);\n                throw initException;\n            }\n        } else {\n            initException = new SchedulerException(\n                    \"Error loading property data from InputStream - InputStream is null.\");\n            throw initException;\n        }\n\n        initialize(props);\n    }\n\n    /**\n     * <p>\n     * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with\n     * the contents of the given <code>Properties</code> object.\n     * </p>\n     */\n    public void initialize(Properties props) {\n        if (propSrc == null) {\n            propSrc = \"an externally provided properties instance.\";\n        }\n\n        this.cfg = new PropertiesParser(props);\n    }\n\n    private Scheduler instantiate() throws SchedulerException {\n        if (cfg == null) {\n            initialize();\n        }\n\n        if (initException != null) {\n            throw initException;\n        }\n\n        JobStore js;\n        ThreadPool tp;\n        QuartzScheduler qs = null;\n        DBConnectionManager dbMgr = null;\n        String instanceIdGeneratorClass = null;\n        Properties tProps;\n        String userTXLocation = null;\n        boolean wrapJobInTx = false;\n        boolean autoId = false;\n        long idleWaitTime = -1;\n        long dbFailureRetry = 15000L; // 15 secs\n        String classLoadHelperClass;\n        String jobFactoryClass;\n        ThreadExecutor threadExecutor;\n\n\n        SchedulerRepository schedRep = SchedulerRepository.getInstance();\n\n        // Get Scheduler Properties\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String schedName = cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,\n                \"QuartzScheduler\");\n\n        String threadName = cfg.getStringProperty(PROP_SCHED_THREAD_NAME,\n                schedName + \"_QuartzSchedulerThread\");\n\n        String schedInstId = cfg.getStringProperty(PROP_SCHED_INSTANCE_ID,\n                DEFAULT_INSTANCE_ID);\n\n        if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) {\n            autoId = true;\n            instanceIdGeneratorClass = cfg.getStringProperty(\n                    PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS,\n                    \"org.quartz.simpl.SimpleInstanceIdGenerator\");\n        }\n        else if (schedInstId.equals(SYSTEM_PROPERTY_AS_INSTANCE_ID)) {\n            autoId = true;\n            instanceIdGeneratorClass = \n                    \"org.quartz.simpl.SystemPropertyInstanceIdGenerator\";\n        }\n\n        userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL,\n                userTXLocation);\n        if (userTXLocation != null && userTXLocation.trim().isEmpty()) {\n            userTXLocation = null;\n        }\n\n        classLoadHelperClass = cfg.getStringProperty(\n                PROP_SCHED_CLASS_LOAD_HELPER_CLASS,\n                \"org.quartz.simpl.CascadingClassLoadHelper\");\n        wrapJobInTx = cfg.getBooleanProperty(PROP_SCHED_WRAP_JOB_IN_USER_TX,\n                wrapJobInTx);\n\n        jobFactoryClass = cfg.getStringProperty(\n                PROP_SCHED_JOB_FACTORY_CLASS, null);\n\n        idleWaitTime = cfg.getLongProperty(PROP_SCHED_IDLE_WAIT_TIME,\n                idleWaitTime);\n        if(idleWaitTime > -1 && idleWaitTime < 1000) {\n            throw new SchedulerException(\"org.quartz.scheduler.idleWaitTime of less than 1000ms is not legal.\");\n        }\n        \n        dbFailureRetry = cfg.getLongProperty(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry);\n        if (dbFailureRetry < 0) {\n            throw new SchedulerException(PROP_SCHED_DB_FAILURE_RETRY_INTERVAL + \" of less than 0 ms is not legal.\");\n        }\n\n        boolean makeSchedulerThreadDaemon =\n            cfg.getBooleanProperty(PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON);\n\n        boolean threadsInheritInitializersClassLoader =\n            cfg.getBooleanProperty(PROP_SCHED_SCHEDULER_THREADS_INHERIT_CONTEXT_CLASS_LOADER_OF_INITIALIZING_THREAD);\n\n        long batchTimeWindow = cfg.getLongProperty(PROP_SCHED_BATCH_TIME_WINDOW, 0L);\n        int maxBatchSize = cfg.getIntProperty(PROP_SCHED_MAX_BATCH_SIZE, 1);\n\n        boolean interruptJobsOnShutdown = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN, false);\n        boolean interruptJobsOnShutdownWithWait = cfg.getBooleanProperty(PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT, false);\n\n        boolean jmxExport = cfg.getBooleanProperty(PROP_SCHED_JMX_EXPORT);\n        String jmxObjectName = cfg.getStringProperty(PROP_SCHED_JMX_OBJECT_NAME);\n        \n        boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY);\n        String jmxProxyClass = cfg.getStringProperty(PROP_SCHED_JMX_PROXY_CLASS);\n\n        boolean rmiExport = cfg.getBooleanProperty(PROP_SCHED_RMI_EXPORT, false);\n        boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY, false);\n        String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST, \"localhost\");\n        int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099);\n        int rmiServerPort = cfg.getIntProperty(PROP_SCHED_RMI_SERVER_PORT, -1);\n        String rmiCreateRegistry = cfg.getStringProperty(\n                PROP_SCHED_RMI_CREATE_REGISTRY,\n                QuartzSchedulerResources.CREATE_REGISTRY_NEVER);\n        String rmiBindName = cfg.getStringProperty(PROP_SCHED_RMI_BIND_NAME);\n\n        if (jmxProxy && rmiProxy) {\n            throw new SchedulerConfigException(\"Cannot proxy both RMI and JMX.\");\n        }\n        \n        boolean managementRESTServiceEnabled = cfg.getBooleanProperty(MANAGEMENT_REST_SERVICE_ENABLED, false);\n        String managementRESTServiceHostAndPort = cfg.getStringProperty(MANAGEMENT_REST_SERVICE_HOST_PORT, \"0.0.0.0:9889\");\n\n        Properties schedCtxProps = cfg.getPropertyGroup(PROP_SCHED_CONTEXT_PREFIX, true);\n\n        // If Proxying to remote scheduler, short-circuit here...\n        // ~~~~~~~~~~~~~~~~~~\n        if (rmiProxy) {\n\n            if (autoId) {\n                schedInstId = DEFAULT_INSTANCE_ID;\n            }\n\n            String uid = (rmiBindName == null) ? QuartzSchedulerResources.getUniqueIdentifier(\n                    schedName, schedInstId) : rmiBindName;\n\n            RemoteScheduler remoteScheduler = new RemoteScheduler(uid, rmiHost, rmiPort);\n\n            schedRep.bind(remoteScheduler);\n\n            return remoteScheduler;\n        }\n\n\n        // Create class load helper\n        ClassLoadHelper loadHelper;\n        try {\n            loadHelper = (ClassLoadHelper) loadClass(classLoadHelperClass).getDeclaredConstructor().newInstance();\n        } catch (Exception e) {\n            throw new SchedulerConfigException(\n                    \"Unable to instantiate class load helper class: \"\n                            + e.getMessage(), e);\n        }\n        loadHelper.initialize();\n\n        // If Proxying to remote JMX scheduler, short-circuit here...\n        // ~~~~~~~~~~~~~~~~~~\n        if (jmxProxy) {\n            if (autoId) {\n                schedInstId = DEFAULT_INSTANCE_ID;\n            }\n\n            if (jmxProxyClass == null) {\n                throw new SchedulerConfigException(\"No JMX Proxy Scheduler class provided\");\n            }\n\n            RemoteMBeanScheduler jmxScheduler;\n            try {\n                jmxScheduler = (RemoteMBeanScheduler) loadHelper.loadClass(jmxProxyClass).getDeclaredConstructor()\n                        .newInstance();\n            } catch (Exception e) {\n                throw new SchedulerConfigException(\n                        \"Unable to instantiate RemoteMBeanScheduler class.\", e);\n            }\n\n            if (jmxObjectName == null) {\n                jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);\n            }\n\n            jmxScheduler.setSchedulerObjectName(jmxObjectName);\n\n            tProps = cfg.getPropertyGroup(PROP_SCHED_JMX_PROXY, true);\n            try {\n                setBeanProps(jmxScheduler, tProps);\n            } catch (Exception e) {\n                initException = new SchedulerException(\"RemoteMBeanScheduler class '\"\n                        + jmxProxyClass + \"' props could not be configured.\", e);\n                throw initException;\n            }\n\n            jmxScheduler.initialize();\n\n            schedRep.bind(jmxScheduler);\n\n            return jmxScheduler;\n        }\n\n        \n        JobFactory jobFactory = null;\n        if(jobFactoryClass != null) {\n            try {\n                jobFactory = (JobFactory) loadHelper.loadClass(jobFactoryClass).getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                throw new SchedulerConfigException(\n                        \"Unable to instantiate JobFactory class: \"\n                                + e.getMessage(), e);\n            }\n\n            tProps = cfg.getPropertyGroup(PROP_SCHED_JOB_FACTORY_PREFIX, true);\n            try {\n                setBeanProps(jobFactory, tProps);\n            } catch (Exception e) {\n                initException = new SchedulerException(\"JobFactory class '\"\n                        + jobFactoryClass + \"' props could not be configured.\", e);\n                throw initException;\n            }\n        }\n\n        InstanceIdGenerator instanceIdGenerator = null;\n        if(instanceIdGeneratorClass != null) {\n            try {\n                instanceIdGenerator = (InstanceIdGenerator) loadHelper.loadClass(instanceIdGeneratorClass)\n                        .getDeclaredConstructor()\n                        .newInstance();\n            } catch (Exception e) {\n                throw new SchedulerConfigException(\n                        \"Unable to instantiate InstanceIdGenerator class: \"\n                        + e.getMessage(), e);\n            }\n\n            tProps = cfg.getPropertyGroup(PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX, true);\n            try {\n                setBeanProps(instanceIdGenerator, tProps);\n            } catch (Exception e) {\n                initException = new SchedulerException(\"InstanceIdGenerator class '\"\n                        + instanceIdGeneratorClass + \"' props could not be configured.\", e);\n                throw initException;\n            }\n        }\n\n        // Get ThreadPool Properties\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());\n\n        if (tpClass == null) {\n            initException = new SchedulerException(\n                    \"ThreadPool class not specified. \");\n            throw initException;\n        }\n\n        try {\n            tp = (ThreadPool) loadHelper.loadClass(tpClass).getDeclaredConstructor().newInstance();\n        } catch (Exception e) {\n            initException = new SchedulerException(\"ThreadPool class '\"\n                    + tpClass + \"' could not be instantiated.\", e);\n            throw initException;\n        }\n        tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true);\n        try {\n            setBeanProps(tp, tProps);\n        } catch (Exception e) {\n            initException = new SchedulerException(\"ThreadPool class '\"\n                    + tpClass + \"' props could not be configured.\", e);\n            throw initException;\n        }\n\n        // Get JobStore Properties\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String jsClass = cfg.getStringProperty(PROP_JOB_STORE_CLASS,\n                RAMJobStore.class.getName());\n\n        if (jsClass == null) {\n            initException = new SchedulerException(\n                    \"JobStore class not specified. \");\n            throw initException;\n        }\n\n        try {\n            js = (JobStore) loadHelper.loadClass(jsClass).getDeclaredConstructor().newInstance();\n        } catch (Exception e) {\n            initException = new SchedulerException(\"JobStore class '\" + jsClass\n                    + \"' could not be instantiated.\", e);\n            throw initException;\n        }\n\n        SchedulerDetailsSetter.setDetails(js, schedName, schedInstId);\n\n        tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true, new String[] {PROP_JOB_STORE_LOCK_HANDLER_PREFIX});\n        try {\n            setBeanProps(js, tProps);\n        } catch (Exception e) {\n            initException = new SchedulerException(\"JobStore class '\" + jsClass\n                    + \"' props could not be configured.\", e);\n            throw initException;\n        }\n\n        if (js instanceof JobStoreSupport) {\n            // Install custom lock handler (Semaphore)\n            String lockHandlerClass = cfg.getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS);\n            if (lockHandlerClass != null) {\n                try {\n                    Semaphore lockHandler = (Semaphore) loadHelper.loadClass(lockHandlerClass)\n                            .getDeclaredConstructor().newInstance();\n\n                    tProps = cfg.getPropertyGroup(PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true);\n\n                    // If this lock handler requires the table prefix, add it to its properties.\n                    if (lockHandler instanceof TablePrefixAware) {\n                        tProps.setProperty(\n                                PROP_TABLE_PREFIX, ((JobStoreSupport)js).getTablePrefix());\n                        tProps.setProperty(\n                                PROP_SCHED_NAME, schedName);\n                    }\n\n                    try {\n                        setBeanProps(lockHandler, tProps);\n                    } catch (Exception e) {\n                        initException = new SchedulerException(\"JobStore LockHandler class '\" + lockHandlerClass\n                                + \"' props could not be configured.\", e);\n                        throw initException;\n                    }\n\n                    ((JobStoreSupport)js).setLockHandler(lockHandler);\n                    getLog().info(\"Using custom data access locking (synchronization): {}\", lockHandlerClass);\n                } catch (Exception e) {\n                    initException = new SchedulerException(\"JobStore LockHandler class '\" + lockHandlerClass\n                            + \"' could not be instantiated.\", e);\n                    throw initException;\n                }\n            }\n        }\n\n        // Set up any DataSources\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);\n        for (String dsName : dsNames) {\n            PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(\n                    PROP_DATASOURCE_PREFIX + \".\" + dsName, true));\n\n            String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);\n\n            // custom connectionProvider...\n            if (cpClass != null) {\n                ConnectionProvider cp;\n                try {\n                    cp = (ConnectionProvider) loadHelper.loadClass(cpClass).getDeclaredConstructor().newInstance();\n                } catch (Exception e) {\n                    initException = new SchedulerException(\"ConnectionProvider class '\" + cpClass\n                            + \"' could not be instantiated.\", e);\n                    throw initException;\n                }\n\n                try {\n                    // remove the class name, so it isn't attempted to be set\n                    pp.getUnderlyingProperties().remove(\n                            PROP_CONNECTION_PROVIDER_CLASS);\n\n                    if (cp instanceof PoolingConnectionProvider) {\n                        populateProviderWithExtraProps((PoolingConnectionProvider) cp, pp.getUnderlyingProperties());\n                    } else {\n                        setBeanProps(cp, pp.getUnderlyingProperties());\n                    }\n                    cp.initialize();\n                } catch (Exception e) {\n                    initException = new SchedulerException(\"ConnectionProvider class '\" + cpClass\n                            + \"' props could not be configured.\", e);\n                    throw initException;\n                }\n\n                dbMgr = DBConnectionManager.getInstance();\n                dbMgr.addConnectionProvider(dsName, cp);\n            } else {\n                String dsJndi = pp.getStringProperty(PROP_DATASOURCE_JNDI_URL, null);\n\n                if (dsJndi != null) {\n                    boolean dsAlwaysLookup = pp.getBooleanProperty(\n                            PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP);\n                    String dsJndiInitial = pp.getStringProperty(\n                            PROP_DATASOURCE_JNDI_INITIAL);\n                    String dsJndiProvider = pp.getStringProperty(\n                            PROP_DATASOURCE_JNDI_PROVIDER);\n                    String dsJndiPrincipal = pp.getStringProperty(\n                            PROP_DATASOURCE_JNDI_PRINCIPAL);\n                    String dsJndiCredentials = pp.getStringProperty(\n                            PROP_DATASOURCE_JNDI_CREDENTIALS);\n                    Properties props = null;\n                    if (null != dsJndiInitial || null != dsJndiProvider\n                            || null != dsJndiPrincipal || null != dsJndiCredentials) {\n                        props = new Properties();\n                        if (dsJndiInitial != null) {\n                            props.put(PROP_DATASOURCE_JNDI_INITIAL,\n                                    dsJndiInitial);\n                        }\n                        if (dsJndiProvider != null) {\n                            props.put(PROP_DATASOURCE_JNDI_PROVIDER,\n                                    dsJndiProvider);\n                        }\n                        if (dsJndiPrincipal != null) {\n                            props.put(PROP_DATASOURCE_JNDI_PRINCIPAL,\n                                    dsJndiPrincipal);\n                        }\n                        if (dsJndiCredentials != null) {\n                            props.put(PROP_DATASOURCE_JNDI_CREDENTIALS,\n                                    dsJndiCredentials);\n                        }\n                    }\n                    JNDIConnectionProvider cp = new JNDIConnectionProvider(dsJndi,\n                            props, dsAlwaysLookup);\n                    dbMgr = DBConnectionManager.getInstance();\n                    dbMgr.addConnectionProvider(dsName, cp);\n                } else {\n                    String poolingProvider = pp.getStringProperty(PoolingConnectionProvider.POOLING_PROVIDER);\n                    String dsDriver = pp.getStringProperty(PoolingConnectionProvider.DB_DRIVER);\n                    String dsURL = pp.getStringProperty(PoolingConnectionProvider.DB_URL);\n\n                    if (dsDriver == null) {\n                        initException = new SchedulerException(\n                                \"Driver not specified for DataSource: \"\n                                        + dsName);\n                        throw initException;\n                    }\n                    if (dsURL == null) {\n                        initException = new SchedulerException(\n                                \"DB URL not specified for DataSource: \"\n                                        + dsName);\n                        throw initException;\n                    }\n                    // we load even these \"core\" providers by class name in order to avoid a static dependency on\n                    // the c3p0 and hikaricp libraries\n                    if (poolingProvider != null && poolingProvider.equals(PoolingConnectionProvider.POOLING_PROVIDER_HIKARICP)) {\n                        cpClass = \"org.quartz.utils.HikariCpPoolingConnectionProvider\";\n                    } else {\n                        cpClass = \"org.quartz.utils.C3p0PoolingConnectionProvider\";\n                    }\n                    log.info(\"Using ConnectionProvider class '\" + cpClass + \"' for data source '\" + dsName + \"'\");\n\n                    try {\n                        ConnectionProvider cp;\n                        try {\n                            Constructor constructor = loadHelper.loadClass(cpClass).getConstructor(Properties.class);\n                            cp = (ConnectionProvider) constructor.newInstance(pp.getUnderlyingProperties());\n                        } catch (Exception e) {\n                            initException = new SchedulerException(\"ConnectionProvider class '\" + cpClass\n                                    + \"' could not be instantiated.\", e);\n                            throw initException;\n                        }\n                        dbMgr = DBConnectionManager.getInstance();\n                        dbMgr.addConnectionProvider(dsName, cp);\n\n                        // Populate the underlying C3P0/HikariCP data source pool properties\n                        populateProviderWithExtraProps((PoolingConnectionProvider) cp, pp.getUnderlyingProperties());\n                    } catch (Exception sqle) {\n                        initException = new SchedulerException(\n                                \"Could not initialize DataSource: \" + dsName,\n                                sqle);\n                        throw initException;\n                    }\n                }\n\n            }\n\n        }\n\n        // Set up any SchedulerPlugins\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String[] pluginNames = cfg.getPropertyGroups(PROP_PLUGIN_PREFIX);\n        SchedulerPlugin[] plugins = new SchedulerPlugin[pluginNames.length];\n        for (int i = 0; i < pluginNames.length; i++) {\n            Properties pp = cfg.getPropertyGroup(PROP_PLUGIN_PREFIX + \".\"\n                    + pluginNames[i], true);\n\n            String plugInClass = pp.getProperty(PROP_PLUGIN_CLASS, null);\n\n            if (plugInClass == null) {\n                initException = new SchedulerException(\n                        \"SchedulerPlugin class not specified for plugin '\"\n                                + pluginNames[i] + \"'\");\n                throw initException;\n            }\n            SchedulerPlugin plugin;\n            try {\n                plugin = (SchedulerPlugin)\n                        loadHelper.loadClass(plugInClass).getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"SchedulerPlugin class '\" + plugInClass\n                                + \"' could not be instantiated.\", e);\n                throw initException;\n            }\n            try {\n                setBeanProps(plugin, pp);\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"JobStore SchedulerPlugin '\" + plugInClass\n                                + \"' props could not be configured.\", e);\n                throw initException;\n            }\n\n            plugins[i] = plugin;\n        }\n\n        // Set up any JobListeners\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        Class<?>[] strArg = new Class[] { String.class };\n        String[] jobListenerNames = cfg.getPropertyGroups(PROP_JOB_LISTENER_PREFIX);\n        JobListener[] jobListeners = new JobListener[jobListenerNames.length];\n        for (int i = 0; i < jobListenerNames.length; i++) {\n            Properties lp = cfg.getPropertyGroup(PROP_JOB_LISTENER_PREFIX + \".\"\n                    + jobListenerNames[i], true);\n\n            String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null);\n\n            if (listenerClass == null) {\n                initException = new SchedulerException(\n                        \"JobListener class not specified for listener '\"\n                                + jobListenerNames[i] + \"'\");\n                throw initException;\n            }\n            JobListener listener;\n            try {\n                listener = (JobListener)\n                        loadHelper.loadClass(listenerClass).getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"JobListener class '\" + listenerClass\n                                + \"' could not be instantiated.\", e);\n                throw initException;\n            }\n            try {\n                Method nameSetter = null;\n                try { \n                    nameSetter = listener.getClass().getMethod(\"setName\", strArg);\n                }\n                catch(NoSuchMethodException ignore) { \n                    /* do nothing */ \n                }\n                if(nameSetter != null) {\n                    nameSetter.invoke(listener, new Object[] {jobListenerNames[i] } );\n                }\n                setBeanProps(listener, lp);\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"JobListener '\" + listenerClass\n                                + \"' props could not be configured.\", e);\n                throw initException;\n            }\n            jobListeners[i] = listener;\n        }\n\n        // Set up any TriggerListeners\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String[] triggerListenerNames = cfg.getPropertyGroups(PROP_TRIGGER_LISTENER_PREFIX);\n        TriggerListener[] triggerListeners = new TriggerListener[triggerListenerNames.length];\n        for (int i = 0; i < triggerListenerNames.length; i++) {\n            Properties lp = cfg.getPropertyGroup(PROP_TRIGGER_LISTENER_PREFIX + \".\"\n                    + triggerListenerNames[i], true);\n\n            String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null);\n\n            if (listenerClass == null) {\n                initException = new SchedulerException(\n                        \"TriggerListener class not specified for listener '\"\n                                + triggerListenerNames[i] + \"'\");\n                throw initException;\n            }\n            TriggerListener listener;\n            try {\n                listener = (TriggerListener)\n                        loadHelper.loadClass(listenerClass).getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"TriggerListener class '\" + listenerClass\n                                + \"' could not be instantiated.\", e);\n                throw initException;\n            }\n            try {\n                Method nameSetter = null;\n                try { \n                    nameSetter = listener.getClass().getMethod(\"setName\", strArg);\n                }\n                catch(NoSuchMethodException ignore) { /* do nothing */ }\n                if(nameSetter != null) {\n                    nameSetter.invoke(listener, new Object[] {triggerListenerNames[i] } );\n                }\n                setBeanProps(listener, lp);\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"TriggerListener '\" + listenerClass\n                                + \"' props could not be configured.\", e);\n                throw initException;\n            }\n            triggerListeners[i] = listener;\n        }\n\n        boolean tpInited = false;\n        boolean qsInited = false;\n\n\n        // Get ThreadExecutor Properties\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n        String threadExecutorClass = cfg.getStringProperty(PROP_THREAD_EXECUTOR_CLASS);\n        if (threadExecutorClass != null) {\n            tProps = cfg.getPropertyGroup(PROP_THREAD_EXECUTOR, true);\n            try {\n                threadExecutor = (ThreadExecutor) loadHelper.loadClass(threadExecutorClass)\n                        .getDeclaredConstructor()\n                        .newInstance();\n                log.info(\"Using custom implementation for ThreadExecutor: {}\", threadExecutorClass);\n\n                setBeanProps(threadExecutor, tProps);\n            } catch (Exception e) {\n                initException = new SchedulerException(\n                        \"ThreadExecutor class '\" + threadExecutorClass + \"' could not be instantiated.\", e);\n                throw initException;\n            }\n        } else {\n            log.info(\"Using default implementation for ThreadExecutor\");\n            threadExecutor = new DefaultThreadExecutor();\n        }\n\n\n\n        // Fire everything up\n        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n        try {\n                \n    \n            JobRunShellFactory jrsf; // Create correct run-shell factory...\n    \n            if (userTXLocation != null) {\n                UserTransactionHelper.setUserTxLocation(userTXLocation);\n            }\n    \n            if (wrapJobInTx) {\n                jrsf = new JTAJobRunShellFactory();\n            } else {\n                jrsf = new JTAAnnotationAwareJobRunShellFactory();\n            }\n    \n            if (autoId) {\n                try {\n                  schedInstId = DEFAULT_INSTANCE_ID;\n                  if (js.isClustered()) {\n                      schedInstId = instanceIdGenerator.generateInstanceId();\n                  }\n                } catch (Exception e) {\n                    getLog().error(\"Couldn't generate instance Id!\", e);\n                    throw new IllegalStateException(\"Cannot run without an instance id.\");\n                }\n            }\n\n            if (js.getClass().getName().startsWith(\"org.terracotta.quartz\")) {\n                try {\n                    String uuid = (String) js.getClass().getMethod(\"getUUID\").invoke(js);\n                    if(schedInstId.equals(DEFAULT_INSTANCE_ID)) {\n                        schedInstId = \"TERRACOTTA_CLUSTERED,node=\" + uuid;\n                        if (jmxObjectName == null) {\n                            jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);\n                        }\n                    } else if(jmxObjectName == null) {\n                        jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId + \",node=\" + uuid);\n                    }\n                } catch(Exception e) {\n                    throw new RuntimeException(\"Problem obtaining node id from TerracottaJobStore.\", e);\n                }\n\n                if(null == cfg.getStringProperty(PROP_SCHED_JMX_EXPORT)) {\n                    jmxExport = true;\n                }\n            }\n            \n            if (js instanceof JobStoreSupport) {\n                JobStoreSupport jjs = (JobStoreSupport)js;\n                jjs.setDbRetryInterval(dbFailureRetry);\n                if(threadsInheritInitializersClassLoader)\n                    jjs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitializersClassLoader);\n                \n                jjs.setThreadExecutor(threadExecutor);\n            }\n    \n            QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();\n            rsrcs.setName(schedName);\n            rsrcs.setThreadName(threadName);\n            rsrcs.setInstanceId(schedInstId);\n            rsrcs.setJobRunShellFactory(jrsf);\n            rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);\n            rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitializersClassLoader);\n            rsrcs.setBatchTimeWindow(batchTimeWindow);\n            rsrcs.setMaxBatchSize(maxBatchSize);\n            rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown);\n            rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait);\n            rsrcs.setJMXExport(jmxExport);\n            rsrcs.setJMXObjectName(jmxObjectName);\n\n            if (managementRESTServiceEnabled) {\n                ManagementRESTServiceConfiguration managementRESTServiceConfiguration = new ManagementRESTServiceConfiguration();\n                managementRESTServiceConfiguration.setBind(managementRESTServiceHostAndPort);\n                managementRESTServiceConfiguration.setEnabled(managementRESTServiceEnabled);\n                rsrcs.setManagementRESTServiceConfiguration(managementRESTServiceConfiguration);\n            }\n    \n            if (rmiExport) {\n                rsrcs.setRMIRegistryHost(rmiHost);\n                rsrcs.setRMIRegistryPort(rmiPort);\n                rsrcs.setRMIServerPort(rmiServerPort);\n                rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry);\n                rsrcs.setRMIBindName(rmiBindName);\n            }\n    \n            SchedulerDetailsSetter.setDetails(tp, schedName, schedInstId);\n\n            rsrcs.setThreadExecutor(threadExecutor);\n            threadExecutor.initialize();\n\n            rsrcs.setThreadPool(tp);\n            if(tp instanceof SimpleThreadPool) {\n                if(threadsInheritInitializersClassLoader)\n                    ((SimpleThreadPool)tp).setThreadsInheritContextClassLoaderOfInitializingThread(threadsInheritInitializersClassLoader);\n            }\n            tp.initialize();\n            tpInited = true;\n    \n            rsrcs.setJobStore(js);\n    \n            // add plugins\n            for (SchedulerPlugin plugin : plugins) {\n                rsrcs.addSchedulerPlugin(plugin);\n            }\n    \n            qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry);\n            qsInited = true;\n    \n            // Create Scheduler ref...\n            Scheduler scheduler = instantiate(rsrcs, qs);\n    \n            // set job factory if specified\n            if(jobFactory != null) {\n                qs.setJobFactory(jobFactory);\n            }\n    \n            // Initialize plugins now that we have a Scheduler instance.\n            for (int i = 0; i < plugins.length; i++) {\n                plugins[i].initialize(pluginNames[i], scheduler, loadHelper);\n            }\n    \n            // add listeners\n            for (JobListener jobListener : jobListeners) {\n                qs.getListenerManager().addJobListener(jobListener, EverythingMatcher.allJobs());\n            }\n            for (TriggerListener triggerListener : triggerListeners) {\n                qs.getListenerManager().addTriggerListener(triggerListener, EverythingMatcher.allTriggers());\n            }\n    \n            // set scheduler context data...\n            for(Object key: schedCtxProps.keySet()) {\n                String val = schedCtxProps.getProperty((String) key);    \n                scheduler.getContext().put((String)key, val);\n            }\n    \n            // fire up job store, and runshell factory\n    \n            js.setInstanceId(schedInstId);\n            js.setInstanceName(schedName);\n            js.setThreadPoolSize(tp.getPoolSize());\n            js.initialize(loadHelper, qs.getSchedulerSignaler());\n\n            jrsf.initialize(scheduler);\n            \n            qs.initialize();\n\n            getLog().info(\"Quartz scheduler '{}' initialized from {}\", scheduler.getSchedulerName(), propSrc);\n\n            getLog().info(\"Quartz scheduler version: {}\", qs.getVersion());\n    \n            // prevents the repository from being garbage collected\n            qs.addNoGCObject(schedRep);\n            // prevents the db manager from being garbage collected\n            if (dbMgr != null) {\n                qs.addNoGCObject(dbMgr);\n            }\n    \n            schedRep.bind(scheduler);\n            return scheduler;\n        }\n        catch(SchedulerException | Error | RuntimeException e) {\n            shutdownFromInstantiateException(tp, qs, tpInited, qsInited);\n            throw e;\n        }\n    }\n\n    private void populateProviderWithExtraProps(PoolingConnectionProvider cp, Properties props) throws Exception {\n        Properties copyProps = new Properties();\n        copyProps.putAll(props);\n\n        // Remove all the default properties first (they don't always match to setter name, and they are already\n        // been set!)\n        copyProps.remove(PoolingConnectionProvider.DB_DRIVER);\n        copyProps.remove(PoolingConnectionProvider.DB_URL);\n        copyProps.remove(PoolingConnectionProvider.DB_USER);\n        copyProps.remove(PoolingConnectionProvider.DB_PASSWORD);\n        copyProps.remove(PoolingConnectionProvider.DB_MAX_CONNECTIONS);\n        copyProps.remove(PoolingConnectionProvider.DB_VALIDATION_QUERY);\n        copyProps.remove(PoolingConnectionProvider.POOLING_PROVIDER);\n\n        if (cp instanceof C3p0PoolingConnectionProvider) {\n            copyProps.remove(C3p0PoolingConnectionProvider.DB_MAX_CACHED_STATEMENTS_PER_CONNECTION);\n            copyProps.remove(C3p0PoolingConnectionProvider.DB_VALIDATE_ON_CHECKOUT);\n            copyProps.remove(C3p0PoolingConnectionProvider.DB_IDLE_VALIDATION_SECONDS);\n            copyProps.remove(C3p0PoolingConnectionProvider.DB_DISCARD_IDLE_CONNECTIONS_SECONDS);\n        }\n\n        setBeanProps(cp.getDataSource(), copyProps);\n    }\n\n    private void shutdownFromInstantiateException(ThreadPool tp, QuartzScheduler qs, boolean tpInited, boolean qsInited) {\n        try {\n            if(qsInited)\n                qs.shutdown(false);\n            else if(tpInited)\n                tp.shutdown(false);\n        } catch (Exception e) {\n            getLog().error(\"Got another exception while shutting down after instantiation exception\", e);\n        }\n    }\n\n    protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) {\n\n        return new StdScheduler(qs);\n    }\n\n\n    private void setBeanProps(Object obj, Properties props)\n        throws NoSuchMethodException, IllegalAccessException,\n            java.lang.reflect.InvocationTargetException,\n            IntrospectionException, SchedulerConfigException {\n        props.remove(\"class\");\n        props.remove(PoolingConnectionProvider.POOLING_PROVIDER);\n\n        BeanInfo bi = Introspector.getBeanInfo(obj.getClass());\n        PropertyDescriptor[] propDescs = bi.getPropertyDescriptors();\n        PropertiesParser pp = new PropertiesParser(props);\n\n        java.util.Enumeration<Object> keys = props.keys();\n        while (keys.hasMoreElements()) {\n            String name = (String) keys.nextElement();\n            String c = name.substring(0, 1).toUpperCase(Locale.US);\n            String methName = \"set\" + c + name.substring(1);\n\n            java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs);\n\n            try {\n                if (setMeth == null) {\n                    throw new NoSuchMethodException(\n                            \"No setter for property '\" + name + \"'\");\n                }\n\n                Class<?>[] params = setMeth.getParameterTypes();\n                if (params.length != 1) {\n                    throw new NoSuchMethodException(\n                        \"No 1-argument setter for property '\" + name + \"'\");\n                }\n                \n                // does the property value reference another property's value? If so, swap to look at its value\n                PropertiesParser refProps = pp;\n                String refName = pp.getStringProperty(name);\n                if(refName != null && refName.startsWith(\"$@\")) {\n                    refName =  refName.substring(2);\n                    refProps = cfg;\n                }\n                else\n                    refName = name;\n                \n                if (params[0].equals(int.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getIntProperty(refName)});\n                } else if (params[0].equals(long.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getLongProperty(refName)});\n                } else if (params[0].equals(float.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getFloatProperty(refName)});\n                } else if (params[0].equals(double.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getDoubleProperty(refName)});\n                } else if (params[0].equals(boolean.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getBooleanProperty(refName)});\n                } else if (params[0].equals(String.class)) {\n                    setMeth.invoke(obj, new Object[]{refProps.getStringProperty(refName)});\n                } else {\n                    throw new NoSuchMethodException(\n                            \"No primitive-type setter for property '\" + name\n                                    + \"'\");\n                }\n            } catch (NumberFormatException nfe) {\n                throw new SchedulerConfigException(\"Could not parse property '\"\n                        + name + \"' into correct data type: \" + nfe);\n            }\n        }\n    }\n\n    private java.lang.reflect.Method getSetMethod(String name,\n            PropertyDescriptor[] props) {\n        for (PropertyDescriptor prop : props) {\n            Method wMeth = prop.getWriteMethod();\n\n            if (wMeth != null && wMeth.getName().equals(name)) {\n                return wMeth;\n            }\n        }\n\n        return null;\n    }\n\n    private Class<?> loadClass(String className) throws ClassNotFoundException, SchedulerConfigException {\n\n        try {\n            ClassLoader cl = findClassLoader();\n            if(cl != null)\n                return cl.loadClass(className);\n            throw new SchedulerConfigException(\"Unable to find a class loader on the current thread or class.\");\n        } catch (ClassNotFoundException e) {\n            if(getClass().getClassLoader() != null)\n                return getClass().getClassLoader().loadClass(className);\n            throw e;\n        }\n    }\n\n    private ClassLoader findClassLoader() {\n        // work-around set context loader for windows-service started jvms (QUARTZ-748)\n        if(Thread.currentThread().getContextClassLoader() == null && getClass().getClassLoader() != null) {\n            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());\n        }\n        return Thread.currentThread().getContextClassLoader();\n    }\n\n    private String getSchedulerName() {\n        return cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,\n                \"QuartzScheduler\");\n    }\n\n    /**\n     * <p>\n     * Returns a handle to the Scheduler produced by this factory.\n     * </p>\n     *\n     * <p>\n     * If one of the <code>initialize</code> methods has not be previously\n     * called, then the default (no-arg) <code>initialize()</code> method\n     * will be called by this method.\n     * </p>\n     */\n    public Scheduler getScheduler() throws SchedulerException {\n        if (cfg == null) {\n            initialize();\n        }\n\n        SchedulerRepository schedRep = SchedulerRepository.getInstance();\n\n        Scheduler sched = schedRep.lookup(getSchedulerName());\n\n        if (sched != null) {\n            if (sched.isShutdown()) {\n                schedRep.remove(getSchedulerName());\n            } else {\n                return sched;\n            }\n        }\n\n        sched = instantiate();\n\n        return sched;\n    }\n\n    /**\n     * <p>\n     * Returns a handle to the default Scheduler, creating it if it does not\n     * yet exist.\n     * </p>\n     *\n     * @see #initialize()\n     */\n    public static Scheduler getDefaultScheduler() throws SchedulerException {\n        StdSchedulerFactory fact = new StdSchedulerFactory();\n\n        return fact.getScheduler();\n    }\n\n    /**\n     * <p>\n     * Returns a handle to the Scheduler with the given name, if it exists (if\n     * it has already been instantiated).\n     * </p>\n     */\n    public Scheduler getScheduler(String schedName) throws SchedulerException {\n        return SchedulerRepository.getInstance().lookup(schedName);\n    }\n\n    /**\n     * <p>\n     * Returns a handle to all known Schedulers (made by any\n     * StdSchedulerFactory instance.).\n     * </p>\n     */\n    public Collection<Scheduler> getAllSchedulers() throws SchedulerException {\n        return SchedulerRepository.getInstance().lookupAll();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/AnnualCalendar.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.calendar;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.TimeZone;\n\nimport org.quartz.Calendar;\n\n/**\n * <p>\n * This implementation of the Calendar excludes a set of days of the year. You\n * may use it to exclude bank holidays which are on the same date every year.\n * </p>\n * \n * @see org.quartz.Calendar\n * @see org.quartz.impl.calendar.BaseCalendar\n * \n * @author Juergen Donnerstag\n */\npublic class AnnualCalendar extends BaseCalendar implements Calendar,\n        Serializable {\n\n    private static final long serialVersionUID = 7346867105876610961L;\n\n    private ArrayList<java.util.Calendar> excludeDays = new ArrayList<>();\n\n    // true, if excludeDays is sorted\n    private boolean dataSorted = false;\n\n    public AnnualCalendar() {\n    }\n\n    public AnnualCalendar(Calendar baseCalendar) {\n        super(baseCalendar);\n    }\n\n    public AnnualCalendar(TimeZone timeZone) {\n        super(timeZone);\n    }\n\n    public AnnualCalendar(Calendar baseCalendar, TimeZone timeZone) {\n        super(baseCalendar, timeZone);\n    }\n\n    @Override\n    public Object clone() {\n        AnnualCalendar clone = (AnnualCalendar) super.clone();\n        clone.excludeDays = new ArrayList<>(excludeDays);\n        return clone;\n    }\n\n    /**\n     * <p>\n     * Get the array which defines the exclude-value of each day of month\n     * </p>\n     */\n    public ArrayList<java.util.Calendar> getDaysExcluded() {\n        return excludeDays;\n    }\n\n    /**\n     * <p>\n     * Return true, if day is defined to be excluded.\n     * </p>\n     */\n    public boolean isDayExcluded(java.util.Calendar day) {\n\n        if (day == null) {\n            throw new IllegalArgumentException(\n                    \"Parameter day must not be null\");\n        }\n\n         // Check baseCalendar first\n        if (! super.isTimeIncluded(day.getTime().getTime())) {\n         return true;\n        } \n        \n        int dmonth = day.get(java.util.Calendar.MONTH);\n        int dday = day.get(java.util.Calendar.DAY_OF_MONTH);\n\n        if (!dataSorted) {\n            Collections.sort(excludeDays, new CalendarComparator());\n            dataSorted = true;\n        }\n\n        for (java.util.Calendar cl : excludeDays) {\n            // remember, the list is sorted\n            if (dmonth < cl.get(java.util.Calendar.MONTH)) {\n                return false;\n            }\n\n            if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) {\n                continue;\n            }\n\n            if (dmonth != cl.get(java.util.Calendar.MONTH)) {\n                continue;\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * <p>\n     * Redefine the list of days excluded. The ArrayList \n     * should contain <code>java.util.Calendar</code> objects. \n     * </p>\n     */\n    public void setDaysExcluded(ArrayList<java.util.Calendar> days) {\n        if (days == null) {\n            excludeDays = new ArrayList<>();\n        } else {\n            excludeDays = days;\n        }\n\n        dataSorted = false;\n    }\n\n    /**\n     * <p>\n     * Redefine a certain day to be excluded (true) or included (false).\n     * </p>\n     */\n    public void setDayExcluded(java.util.Calendar day, boolean exclude) {\n        if (exclude) {\n            if (isDayExcluded(day)) {\n                return;\n            }\n\n            excludeDays.add(day);\n            dataSorted = false;\n        } else {\n            if (!isDayExcluded(day)) {\n                return;\n            }\n\n            removeExcludedDay(day, true);\n        }\n    }\n\n    /**\n     * Remove the given day from the list of excluded days\n     *  \n     * @param day the day to exclude\n     */\n    public void removeExcludedDay(java.util.Calendar day) {\n        removeExcludedDay(day, false);\n    }\n    \n    private void removeExcludedDay(java.util.Calendar day, boolean isChecked) {\n        if (! isChecked &&\n            ! isDayExcluded(day)) {\n            return;\n        }\n        \n        // Fast way, see if exact day object was already in list\n        if (this.excludeDays.remove(day)) {\n            return;\n        }\n        \n        int dmonth = day.get(java.util.Calendar.MONTH);\n        int dday = day.get(java.util.Calendar.DAY_OF_MONTH);\n        \n        // Since there is no guarantee that the given day is in the arraylist with the exact same year\n        // search for the object based on month and day of month in the list and remove it\n        for (java.util.Calendar cl : excludeDays) {\n            if (dmonth != cl.get(java.util.Calendar.MONTH)) {\n                continue;\n            }\n\n            if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) {\n                continue;\n            }\n\n            day = cl;\n            break;\n        }\n        \n        this.excludeDays.remove(day);\n    }\n\n    \n    /**\n     * <p>\n     * Determine whether the given time (in milliseconds) is 'included' by the\n     * Calendar.\n     * </p>\n     * \n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeStamp) {\n        // Test the base calendar first. Only if the base calendar not already\n        // excludes the time/date, continue evaluating this calendar instance.\n        if (!super.isTimeIncluded(timeStamp)) { return false; }\n\n        java.util.Calendar day = createJavaCalendar(timeStamp);\n\n        return !(isDayExcluded(day));\n    }\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time. Return the original value if timeStamp is\n     * included. Return 0 if all days are excluded.\n     * </p>\n     * \n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public long getNextIncludedTime(long timeStamp) {\n        // Call base calendar implementation first\n        long baseTime = super.getNextIncludedTime(timeStamp);\n        if ((baseTime > 0) && (baseTime > timeStamp)) {\n            timeStamp = baseTime;\n        }\n\n        // Get timestamp for 00:00:00\n        java.util.Calendar day = getStartOfDayJavaCalendar(timeStamp);\n        if (!isDayExcluded(day)) {\n            return timeStamp; // return the original value\n        }\n\n        while (isDayExcluded(day)) {\n            day.add(java.util.Calendar.DATE, 1);\n        }\n\n        return day.getTime().getTime();\n    }\n}\n\nclass CalendarComparator implements Comparator<java.util.Calendar>, Serializable {\n  \n    private static final long serialVersionUID = 7346867105876610961L;\n    \n    public CalendarComparator() {\n    }\n\n\n    public int compare(java.util.Calendar c1, java.util.Calendar c2) {\n        \n        int month1 = c1.get(java.util.Calendar.MONTH);\n        int month2 = c2.get(java.util.Calendar.MONTH);\n        \n        int day1 = c1.get(java.util.Calendar.DAY_OF_MONTH);\n        int day2 = c2.get(java.util.Calendar.DAY_OF_MONTH);\n        \n        if (month1 < month2) {\n            return -1;\n        }\n        if (month1 > month2) {\n            return 1; \n        }\n        if (day1 < day2) {\n            return -1;\n        }\n        if (day1 > day2) {\n            return 1;\n        }\n        return 0;\n      }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/BaseCalendar.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.impl.calendar;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport org.quartz.Calendar;\n\n/**\n * <p>\n * This implementation of the Calendar may be used (you don't have to) as a\n * base class for more sophisticated one's. It merely implements the base\n * functionality required by each Calendar.\n * </p>\n *\n * <p>\n * Regarded as base functionality is the treatment of base calendars. Base\n * calendar allow you to chain (stack) as much calendars as you may need. For\n * example to exclude weekends you may use WeeklyCalendar. In order to exclude\n * holidays as well you may define a WeeklyCalendar instance to be the base\n * calendar for HolidayCalendar instance.\n * </p>\n *\n * @see org.quartz.Calendar\n *\n * @author Juergen Donnerstag\n * @author James House\n */\npublic class BaseCalendar implements Calendar, Serializable, Cloneable {\n\n    private static final long serialVersionUID = 3106623404629760239L;\n\n    // <p>A optional base calendar.</p>\n    private Calendar baseCalendar;\n\n    private String description;\n\n    private TimeZone timeZone;\n\n    public BaseCalendar() {\n    }\n\n    public BaseCalendar(Calendar baseCalendar) {\n        setBaseCalendar(baseCalendar);\n    }\n\n    /**\n     * @param timeZone The time zone to use for this Calendar, <code>null</code>\n     * if <code>{@link TimeZone#getDefault()}</code> should be used\n     */\n    public BaseCalendar(TimeZone timeZone) {\n        setTimeZone(timeZone);\n    }\n\n    /**\n     * @param timeZone The time zone to use for this Calendar, <code>null</code>\n     * if <code>{@link TimeZone#getDefault()}</code> should be used\n     */\n    public BaseCalendar(Calendar baseCalendar, TimeZone timeZone) {\n        setBaseCalendar(baseCalendar);\n        setTimeZone(timeZone);\n    }\n\n    @Override\n    public Object clone()  {\n        try {\n            BaseCalendar clone = (BaseCalendar) super.clone();\n            if (getBaseCalendar() != null) {\n                clone.baseCalendar = (Calendar) getBaseCalendar().clone();\n            }\n            if(getTimeZone() != null)\n                clone.timeZone = (TimeZone) getTimeZone().clone();\n            return clone;\n        } catch (CloneNotSupportedException ex) {\n            throw new IncompatibleClassChangeError(\"Not Cloneable.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Set a new base calendar or remove the existing one\n     * </p>\n     */\n    public void setBaseCalendar(Calendar baseCalendar) {\n        this.baseCalendar = baseCalendar;\n    }\n\n    /**\n     * <p>\n     * Get the base calendar. Will be null, if not set.\n     * </p>\n     */\n    public Calendar getBaseCalendar() {\n        return this.baseCalendar;\n    }\n\n    /**\n     * <p>\n     * Return the description given to the <code>Calendar</code> instance by\n     * its creator (if any).\n     * </p>\n     *\n     * @return null if no description was set.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * <p>\n     * Set a description for the <code>Calendar</code> instance - may be\n     * useful for remembering/displaying the purpose of the calendar, though\n     * the description has no meaning to Quartz.\n     * </p>\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * Returns the time zone for which this <code>Calendar</code> will be\n     * resolved.\n     *\n     * @return This Calendar's timezone, <code>null</code> if Calendar should\n     * use the <code>{@link TimeZone#getDefault()}</code>\n     */\n    public TimeZone getTimeZone() {\n        return timeZone;\n    }\n\n    /**\n     * Sets the time zone for which this <code>Calendar</code> will be resolved.\n     *\n     * @param timeZone The time zone to use for this Calendar, <code>null</code>\n     * if <code>{@link TimeZone#getDefault()}</code> should be used\n     */\n    public void setTimeZone(TimeZone timeZone) {\n        this.timeZone = timeZone;\n    }\n\n    /**\n     * <p>\n     * Check if date/time represented by timeStamp is included. If included\n     * return true. The implementation of BaseCalendar simply calls the base\n     * calendars isTimeIncluded() method if base calendar is set.\n     * </p>\n     *\n     * @see org.quartz.Calendar#isTimeIncluded(long)\n     */\n    public boolean isTimeIncluded(long timeStamp) {\n\n        if (timeStamp <= 0) {\n            throw new IllegalArgumentException(\n                    \"timeStamp must be greater 0\");\n        }\n\n        if (baseCalendar != null) {\n            return baseCalendar.isTimeIncluded(timeStamp);\n        }\n\n        return true;\n    }\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time. Return the original value if timeStamp is\n     * included. Return 0 if all days are excluded.\n     * </p>\n     *\n     * @see org.quartz.Calendar#getNextIncludedTime(long)\n     */\n    public long getNextIncludedTime(long timeStamp) {\n\n        if (timeStamp <= 0) {\n            throw new IllegalArgumentException(\n                    \"timeStamp must be greater 0\");\n        }\n\n        if (baseCalendar != null) {\n            return baseCalendar.getNextIncludedTime(timeStamp);\n        }\n\n        return timeStamp;\n    }\n\n    /**\n     * Build a <code>{@link java.util.Calendar}</code> for the given timeStamp.\n     * The new Calendar will use the <code>BaseCalendar</code> time zone if it\n     * is not <code>null</code>.\n     */\n    protected java.util.Calendar createJavaCalendar(long timeStamp) {\n        java.util.Calendar calendar = createJavaCalendar();\n        calendar.setTime(new Date(timeStamp));\n        return calendar;\n    }\n\n    /**\n     * Build a <code>{@link java.util.Calendar}</code> with the current time.\n     * The new Calendar will use the <code>BaseCalendar</code> time zone if\n     * it is not <code>null</code>.\n     */\n    protected java.util.Calendar createJavaCalendar() {\n        return\n            (getTimeZone() == null) ?\n                java.util.Calendar.getInstance() :\n                java.util.Calendar.getInstance(getTimeZone());\n    }\n\n    /**\n     * Returns the start of the given day as a <code>{@link java.util.Calendar}</code>.\n     * This calculation will take the <code>BaseCalendar</code>\n     * time zone into account if it is not <code>null</code>.\n     *\n     * @param timeInMillis A time containing the desired date for the\n     *                     start-of-day time\n     * @return A <code>{@link java.util.Calendar}</code> set to the start of\n     *         the given day.\n     */\n    protected java.util.Calendar getStartOfDayJavaCalendar(long timeInMillis) {\n        java.util.Calendar startOfDay = createJavaCalendar(timeInMillis);\n        startOfDay.set(java.util.Calendar.HOUR_OF_DAY, 0);\n        startOfDay.set(java.util.Calendar.MINUTE, 0);\n        startOfDay.set(java.util.Calendar.SECOND, 0);\n        startOfDay.set(java.util.Calendar.MILLISECOND, 0);\n        return startOfDay;\n    }\n\n    /**\n     * Returns the end of the given day <code>{@link java.util.Calendar}</code>.\n     * This calculation will take the <code>BaseCalendar</code>\n     * time zone into account if it is not <code>null</code>.\n     *\n     * @param timeInMillis a time containing the desired date for the\n     *                     end-of-day time.\n     * @return A <code>{@link java.util.Calendar}</code> set to the end of\n     *         the given day.\n     */\n    protected java.util.Calendar getEndOfDayJavaCalendar(long timeInMillis) {\n        java.util.Calendar endOfDay = createJavaCalendar(timeInMillis);\n        endOfDay.set(java.util.Calendar.HOUR_OF_DAY, 23);\n        endOfDay.set(java.util.Calendar.MINUTE, 59);\n        endOfDay.set(java.util.Calendar.SECOND, 59);\n        endOfDay.set(java.util.Calendar.MILLISECOND, 999);\n        return endOfDay;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/CronCalendar.java",
    "content": "package org.quartz.impl.calendar;\n\nimport java.text.ParseException;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport org.quartz.Calendar;\nimport org.quartz.CronExpression;\n\n/**\n * This implementation of the Calendar excludes the set of times expressed by a\n * given {@link org.quartz.CronExpression CronExpression}. For example, you \n * could use this calendar to exclude all but business hours (8AM - 5PM) every \n * day using the expression &quot;* * 0-7,18-23 ? * *&quot;. \n * <P>\n * It is important to remember that the cron expression here describes a set of\n * times to be <I>excluded</I> from firing. Whereas the cron expression in \n * {@link org.quartz.CronTrigger CronTrigger} describes a set of times that can\n * be <I>included</I> for firing. Thus, if a <CODE>CronTrigger</CODE> has a \n * given cron expression and is associated with a <CODE>CronCalendar</CODE> with\n * the <I>same</I> expression, the calendar will exclude all the times the \n * trigger includes, and they will cancel each other out. \n * \n * @author Aaron Craven\n */\npublic class CronCalendar extends BaseCalendar {\n    private static final long serialVersionUID = -8172103999750856831L;\n\n    CronExpression cronExpression;\n\n    /**\n     * Create a <CODE>CronCalendar</CODE> with the given cron expression and no\n     * <CODE>baseCalendar</CODE>.\n     *  \n     * @param expression a String representation of the desired cron expression\n     */\n    public CronCalendar(String expression) \n        throws ParseException {\n        this(null, expression, null);\n    }\n\n    /**\n     * Create a <CODE>CronCalendar</CODE> with the given cron expression and \n     * <CODE>baseCalendar</CODE>. \n     * \n     * @param baseCalendar the base calendar for this calendar instance &ndash;\n     *                     see {@link BaseCalendar} for more information on base\n     *                     calendar functionality\n     * @param expression   a String representation of the desired cron expression\n     */\n    public CronCalendar(Calendar baseCalendar,\n            String expression) throws ParseException {\n        this(baseCalendar, expression, null);\n    }\n\n    /**\n     * Create a <CODE>CronCalendar</CODE> with the given cron expression, \n     * <CODE>baseCalendar</CODE>, and <code>TimeZone</code>. \n     * \n     * @param baseCalendar the base calendar for this calendar instance &ndash;\n     *                     see {@link BaseCalendar} for more information on base\n     *                     calendar functionality\n     * @param expression   a String representation of the desired cron expression\n     * @param timeZone\n     *          Specifies for which time zone the <code>expression</code>\n     *          should be interpreted, i.e. the expression 0 0 10 * * ?, is\n     *          resolved to 10:00 am in this time zone.  If \n     *          <code>timeZone</code> is <code>null</code> then \n     *          <code>TimeZone.getDefault()</code> will be used.\n     */\n    public CronCalendar(Calendar baseCalendar,\n            String expression, TimeZone timeZone) throws ParseException {\n        super(baseCalendar);\n        this.cronExpression = new CronExpression(expression);\n        this.cronExpression.setTimeZone(timeZone);\n    }\n    \n    @Override\n    public Object clone() {\n        CronCalendar clone = (CronCalendar) super.clone();\n        clone.cronExpression = new CronExpression(cronExpression);\n        return clone;\n    }\n\n    /**\n     * Returns the time zone for which the <code>CronExpression</code> of\n     * this <code>CronCalendar</code> will be resolved.\n     * <p>\n     * Overrides <code>{@link BaseCalendar#getTimeZone()}</code> to\n     * defer to its <code>CronExpression</code>.\n     * </p>\n     */\n    @Override\n    public TimeZone getTimeZone() {\n        return cronExpression.getTimeZone();\n    }\n\n    /**\n     * Sets the time zone for which the <code>CronExpression</code> of this\n     * <code>CronCalendar</code> will be resolved.  If <code>timeZone</code> \n     * is <code>null</code> then <code>TimeZone.getDefault()</code> will be \n     * used.\n     * <p>\n     * Overrides <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code> to\n     * defer to its <code>CronExpression</code>.\n     * </p>\n     */\n    @Override\n    public void setTimeZone(TimeZone timeZone) {\n        cronExpression.setTimeZone(timeZone);\n    }\n    \n    /**\n     * Determines whether the given time (in milliseconds) is 'included' by the\n     * <CODE>BaseCalendar</CODE>\n     * \n     * @param timeInMillis the date/time to test\n     * @return a boolean indicating whether the specified time is 'included' by\n     *         the <CODE>CronCalendar</CODE>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeInMillis) {        \n        if ((getBaseCalendar() != null) && \n                (!getBaseCalendar().isTimeIncluded(timeInMillis))) {\n            return false;\n        }\n        \n        return (!(cronExpression.isSatisfiedBy(new Date(timeInMillis))));\n    }\n\n    /**\n     * Determines the next time included by the <CODE>CronCalendar</CODE>\n     * after the specified time.\n     * \n     * @param timeInMillis the initial date/time after which to find an \n     *                     included time\n     * @return the time in milliseconds representing the next time included\n     *         after the specified time.\n     */\n    @Override\n    public long getNextIncludedTime(long timeInMillis) {\n        long nextIncludedTime = timeInMillis + 1; //plus on millisecond\n        \n        while (!isTimeIncluded(nextIncludedTime)) {\n\n            //If the time is in a range excluded by this calendar, we can\n            // move to the end of the excluded time range and continue testing\n            // from there. Otherwise, if nextIncludedTime is excluded by the\n            // baseCalendar, ask it the next time it includes and begin testing\n            // from there. Failing this, add one millisecond and continue\n            // testing.\n            if (cronExpression.isSatisfiedBy(new Date(nextIncludedTime))) {\n                nextIncludedTime = cronExpression.getNextInvalidTimeAfter(\n                        new Date(nextIncludedTime)).getTime();\n            } else if ((getBaseCalendar() != null) && \n                    (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){\n                nextIncludedTime = \n                    getBaseCalendar().getNextIncludedTime(nextIncludedTime);\n            } else {\n                nextIncludedTime++;\n            }\n        }\n        \n        return nextIncludedTime;\n    }\n\n    /**\n     * Returns a string representing the properties of the \n     * <CODE>CronCalendar</CODE>\n     * \n     * @return the properties of the CronCalendar in a String format\n     */\n    @Override\n    public String toString() {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"base calendar: [\");\n        if (getBaseCalendar() != null) {\n            buffer.append(getBaseCalendar().toString());\n        } else {\n            buffer.append(\"null\");\n        }\n        buffer.append(\"], excluded cron expression: '\");\n        buffer.append(cronExpression);\n        buffer.append(\"'\");\n        return buffer.toString();\n    }\n    \n    /**\n     * Returns the object representation of the cron expression that defines the\n     * dates and times this calendar excludes.\n     * \n     * @return the cron expression\n     * @see org.quartz.CronExpression\n     */\n    public CronExpression getCronExpression() {\n        return cronExpression;\n    }\n    \n    /**\n     * Sets the cron expression for the calendar to a new value\n     * \n     * @param expression the new string value to build a cron expression from\n     * @throws ParseException\n     *         if the string expression cannot be parsed\n     */\n    public void setCronExpression(String expression) throws ParseException {\n\n        this.cronExpression = new CronExpression(expression);\n    }\n\n    /**\n     * Sets the cron expression for the calendar to a new value\n     * \n     * @param expression the new cron expression\n     */\n    public void setCronExpression(CronExpression expression) {\n        if (expression == null) {\n            throw new IllegalArgumentException(\"expression cannot be null\");\n        }\n        \n        this.cronExpression = expression;\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/DailyCalendar.java",
    "content": "package org.quartz.impl.calendar;\n\nimport java.text.NumberFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.StringTokenizer;\nimport java.util.TimeZone;\n\n/**\n * This implementation of the Calendar excludes (or includes - see below) a \n * specified time range each day. For example, you could use this calendar to \n * exclude business hours (8AM - 5PM) every day. Each <CODE>DailyCalendar</CODE>\n * only allows a single time range to be specified, and that time range may not\n * cross daily boundaries (i.e. you cannot specify a time range from 8PM - 5AM).\n * If the property <CODE>invertTimeRange</CODE> is <CODE>false</CODE> (default), \n * the time range defines a range of times in which triggers are not allowed to\n * fire. If <CODE>invertTimeRange</CODE> is <CODE>true</CODE>, the time range\n * is inverted &ndash; that is, all times <I>outside</I> the defined time range\n * are excluded.\n * <P>\n * Note when using <CODE>DailyCalendar</CODE>, it behaves on the same principals\n * as, for example, {@link org.quartz.impl.calendar.WeeklyCalendar \n * WeeklyCalendar}. <CODE>WeeklyCalendar</CODE> defines a set of days that are\n * excluded <I>every week</I>. Likewise, <CODE>DailyCalendar</CODE> defines a \n * set of times that are excluded <I>every day</I>.\n * \n * @author Mike Funk, Aaron Craven\n */\npublic class DailyCalendar extends BaseCalendar {\n    private static final long serialVersionUID = -7561220099904944039L;\n    \n    private static final String invalidHourOfDay = \"Invalid hour of day: \";\n    private static final String invalidMinute = \"Invalid minute: \";\n    private static final String invalidSecond = \"Invalid second: \";\n    private static final String invalidMillis = \"Invalid millis: \";\n    private static final String invalidTimeRange = \"Invalid time range: \";\n    private static final String separator = \" - \";\n    private static final long oneMillis = 1;\n    private static final String colon = \":\";\n\n    private int rangeStartingHourOfDay;\n    private int rangeStartingMinute;\n    private int rangeStartingSecond;\n    private int rangeStartingMillis;\n    private int rangeEndingHourOfDay;\n    private int rangeEndingMinute;\n    private int rangeEndingSecond;\n    private int rangeEndingMillis;\n    \n    private boolean invertTimeRange = false;\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified strings and no <CODE>baseCalendar</CODE>. \n     * <CODE>rangeStartingTime</CODE> and <CODE>rangeEndingTime</CODE>\n     * must be in the format &quot;HH:MM[:SS[:mmm]]&quot; where:\n     * <UL><LI>HH is the hour of the specified time. The hour should be\n     *         specified using military (24-hour) time and must be in the range\n     *         0 to 23.</LI>\n     *     <LI>MM is the minute of the specified time and must be in the range\n     *         0 to 59.</LI>\n     *     <LI>SS is the second of the specified time and must be in the range\n     *         0 to 59.</LI>\n     *     <LI>mmm is the millisecond of the specified time and must be in the\n     *         range 0 to 999.</LI>\n     *     <LI>items enclosed in brackets ('[', ']') are optional.</LI>\n     *     <LI>The time range starting time must be before the time range ending\n     *         time. Note this means that a time range may not cross daily \n     *         boundaries (10PM - 2AM)</LI>  \n     * </UL>\n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     *  \n     * @param rangeStartingTime a String representing the starting time for the\n     *                          time range\n     * @param rangeEndingTime   a String representing the ending time for the\n     *                          the time range\n     */\n    public DailyCalendar(String rangeStartingTime,\n                         String rangeEndingTime) {\n        super();\n        setTimeRange(rangeStartingTime, rangeEndingTime);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified strings and the specified <CODE>baseCalendar</CODE>. \n     * <CODE>rangeStartingTime</CODE> and <CODE>rangeEndingTime</CODE>\n     * must be in the format &quot;HH:MM[:SS[:mmm]]&quot; where:\n     * <UL><LI>HH is the hour of the specified time. The hour should be\n     *         specified using military (24-hour) time and must be in the range\n     *         0 to 23.</LI>\n     *     <LI>MM is the minute of the specified time and must be in the range\n     *         0 to 59.</LI>\n     *     <LI>SS is the second of the specified time and must be in the range\n     *         0 to 59.</LI>\n     *     <LI>mmm is the millisecond of the specified time and must be in the\n     *         range 0 to 999.</LI>\n     *     <LI>items enclosed in brackets ('[', ']') are optional.</LI>\n     *     <LI>The time range starting time must be before the time range ending\n     *         time. Note this means that a time range may not cross daily \n     *         boundaries (10PM - 2AM)</LI>  \n     * </UL>\n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     * \n     * @param baseCalendar      the base calendar for this calendar instance\n     *                          &ndash; see {@link BaseCalendar} for more\n     *                          information on base calendar functionality\n     * @param rangeStartingTime a String representing the starting time for the\n     *                          time range\n     * @param rangeEndingTime   a String representing the ending time for the\n     *                          time range\n     */\n    public DailyCalendar(org.quartz.Calendar baseCalendar,\n                         String rangeStartingTime,\n                         String rangeEndingTime) {\n        super(baseCalendar);\n        setTimeRange(rangeStartingTime, rangeEndingTime);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and no <CODE>baseCalendar</CODE>. Values are subject to\n     * the following validations:\n     * <UL><LI>Hours must be in the range 0-23 and are expressed using military\n     *         (24-hour) time.</LI>\n     *     <LI>Minutes must be in the range 0-59</LI>\n     *     <LI>Seconds must be in the range 0-59</LI>\n     *     <LI>Milliseconds must be in the range 0-999</LI>\n     *     <LI>The time range starting time must be before the time range ending\n     *         time. Note this means that a time range may not cross daily \n     *         boundaries (10PM - 2AM)</LI>  \n     * </UL>\n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     * \n     * @param rangeStartingHourOfDay the hour of the start of the time range\n     * @param rangeStartingMinute    the minute of the start of the time range\n     * @param rangeStartingSecond    the second of the start of the time range\n     * @param rangeStartingMillis    the millisecond of the start of the time \n     *                               range\n     * @param rangeEndingHourOfDay   the hour of the end of the time range\n     * @param rangeEndingMinute      the minute of the end of the time range\n     * @param rangeEndingSecond      the second of the end of the time range\n     * @param rangeEndingMillis      the millisecond of the start of the time \n     *                               range\n     */\n    public DailyCalendar(int rangeStartingHourOfDay,\n                         int rangeStartingMinute,\n                         int rangeStartingSecond,\n                         int rangeStartingMillis,\n                         int rangeEndingHourOfDay,\n                         int rangeEndingMinute,\n                         int rangeEndingSecond,\n                         int rangeEndingMillis) {\n        super();\n        setTimeRange(rangeStartingHourOfDay,\n                     rangeStartingMinute,\n                     rangeStartingSecond,\n                     rangeStartingMillis,\n                     rangeEndingHourOfDay,\n                     rangeEndingMinute,\n                     rangeEndingSecond,\n                     rangeEndingMillis);\n    }\n    \n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and the specified <CODE>baseCalendar</CODE>. Values are\n     * subject to the following validations:\n     * <UL><LI>Hours must be in the range 0-23 and are expressed using military\n     *         (24-hour) time.</LI>\n     *     <LI>Minutes must be in the range 0-59</LI>\n     *     <LI>Seconds must be in the range 0-59</LI>\n     *     <LI>Milliseconds must be in the range 0-999</LI>\n     *     <LI>The time range starting time must be before the time range ending\n     *         time. Note this means that a time range may not cross daily\n     *         boundaries (10PM - 2AM)</LI>  \n     * </UL> \n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     * \n     * @param baseCalendar              the base calendar for this calendar\n     *                                  instance &ndash; see \n     *                                  {@link BaseCalendar} for more \n     *                                  information on base calendar \n     *                                  functionality\n     * @param rangeStartingHourOfDay the hour of the start of the time range\n     * @param rangeStartingMinute    the minute of the start of the time range\n     * @param rangeStartingSecond    the second of the start of the time range\n     * @param rangeStartingMillis    the millisecond of the start of the time \n     *                               range\n     * @param rangeEndingHourOfDay   the hour of the end of the time range\n     * @param rangeEndingMinute      the minute of the end of the time range\n     * @param rangeEndingSecond      the second of the end of the time range\n     * @param rangeEndingMillis      the millisecond of the start of the time \n     *                               range\n     */\n    public DailyCalendar(org.quartz.Calendar baseCalendar,\n                         int rangeStartingHourOfDay,\n                         int rangeStartingMinute,\n                         int rangeStartingSecond,\n                         int rangeStartingMillis,\n                         int rangeEndingHourOfDay,\n                         int rangeEndingMinute,\n                         int rangeEndingSecond,\n                         int rangeEndingMillis) {\n        super(baseCalendar);\n        setTimeRange(rangeStartingHourOfDay,\n                     rangeStartingMinute,\n                     rangeStartingSecond,\n                     rangeStartingMillis,\n                     rangeEndingHourOfDay,\n                     rangeEndingMinute,\n                     rangeEndingSecond,\n                     rangeEndingMillis);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified <CODE>java.util.Calendar</CODE>s and no \n     * <CODE>baseCalendar</CODE>. The Calendars are subject to the following\n     * considerations:\n     * <UL><LI>Only the time-of-day fields of the specified Calendars will be\n     *         used (the date fields will be ignored)</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time fields are\n     *         are used, it is possible for two Calendars to represent a valid\n     *         time range and \n     *         <CODE>rangeStartingCalendar.after(rangeEndingCalendar) == \n     *         true</CODE>)</I></LI>  \n     * </UL> \n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     * \n     * @param rangeStartingCalendar a java.util.Calendar representing the \n     *                              starting time for the time range\n     * @param rangeEndingCalendar   a java.util.Calendar representing the ending\n     *                              time for the time range\n     */\n    public DailyCalendar(\n                         Calendar rangeStartingCalendar,\n                         Calendar rangeEndingCalendar) {\n        super();\n        setTimeRange(rangeStartingCalendar, rangeEndingCalendar);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified <CODE>java.util.Calendar</CODE>s and the specified \n     * <CODE>baseCalendar</CODE>. The Calendars are subject to the following\n     * considerations:\n     * <UL><LI>Only the time-of-day fields of the specified Calendars will be\n     *         used (the date fields will be ignored)</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time fields are\n     *         are used, it is possible for two Calendars to represent a valid\n     *         time range and \n     *         <CODE>rangeStartingCalendar.after(rangeEndingCalendar) == \n     *         true</CODE>)</I></LI>  \n     * </UL> \n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>\n     * </p>\n     * \n     * @param baseCalendar          the base calendar for this calendar instance\n     *                              &ndash; see {@link BaseCalendar} for more \n     *                              information on base calendar functionality\n     * @param rangeStartingCalendar a java.util.Calendar representing the \n     *                              starting time for the time range\n     * @param rangeEndingCalendar   a java.util.Calendar representing the ending\n     *                              time for the time range\n     */\n    public DailyCalendar(org.quartz.Calendar baseCalendar,\n                         Calendar rangeStartingCalendar,\n                         Calendar rangeEndingCalendar) {\n        super(baseCalendar);\n        setTimeRange(rangeStartingCalendar, rangeEndingCalendar);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and no <CODE>baseCalendar</CODE>. The values are \n     * subject to the following considerations:\n     * <UL><LI>Only the time-of-day portion of the specified values will be\n     *         used</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time value are\n     *         are used, it is possible for the two values to represent a valid\n     *         time range and <CODE>rangeStartingTime &gt; \n     *         rangeEndingTime</CODE>)</I></LI>  \n     * </UL> \n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>.\n     * You should use <code>{@link #DailyCalendar(org.quartz.Calendar, java.util.TimeZone, long, long)}</code>\n     * if you don't want the given <code>rangeStartingTimeInMillis</code> and\n     * <code>rangeEndingTimeInMillis</code> to be evaluated in the default \n     * time zone.\n     * </p>\n     * \n     * @param rangeStartingTimeInMillis a long representing the starting time \n     *                                  for the time range\n     * @param rangeEndingTimeInMillis   a long representing the ending time for\n     *                                  the time range\n     */\n    public DailyCalendar(long rangeStartingTimeInMillis,\n                         long rangeEndingTimeInMillis) {\n        super();\n        setTimeRange(rangeStartingTimeInMillis, \n                     rangeEndingTimeInMillis);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and the specified <CODE>baseCalendar</CODE>. The values\n     * are subject to the following considerations:\n     * <UL><LI>Only the time-of-day portion of the specified values will be\n     *         used</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time value are\n     *         are used, it is possible for the two values to represent a valid\n     *         time range and <CODE>rangeStartingTime &gt; \n     *         rangeEndingTime</CODE>)</I></LI>  \n     * </UL> \n     * \n     * <p>\n     * <b>Note:</b> This <CODE>DailyCalendar</CODE> will use the \n     * <code>{@link TimeZone#getDefault()}</code> time zone unless an explicit \n     * time zone is set via <code>{@link BaseCalendar#setTimeZone(TimeZone)}</code>.\n     * You should use <code>{@link #DailyCalendar(org.quartz.Calendar, java.util.TimeZone, long, long)} </code>\n     * if you don't want the given <code>rangeStartingTimeInMillis</code> and\n     * <code>rangeEndingTimeInMillis</code> to be evaluated in the default \n     * time zone.\n     * </p>\n     * \n     * @param baseCalendar              the base calendar for this calendar\n     *                                  instance &ndash; see {@link \n     *                                  BaseCalendar} for more information on \n     *                                  base calendar functionality\n     * @param rangeStartingTimeInMillis a long representing the starting time \n     *                                  for the time range\n     * @param rangeEndingTimeInMillis   a long representing the ending time for\n     *                                  the time range\n     */\n    public DailyCalendar(org.quartz.Calendar baseCalendar,\n                         long rangeStartingTimeInMillis,\n                         long rangeEndingTimeInMillis) {\n        super(baseCalendar);\n        setTimeRange(rangeStartingTimeInMillis,\n                     rangeEndingTimeInMillis);\n    }\n    \n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and no <CODE>baseCalendar</CODE>. The values are \n     * subject to the following considerations:\n     * <UL><LI>Only the time-of-day portion of the specified values will be\n     *         used</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time value are\n     *         are used, it is possible for the two values to represent a valid\n     *         time range and <CODE>rangeStartingTime &gt; \n     *         rangeEndingTime</CODE>)</I></LI>  \n     * </UL> \n     * \n     * @param timeZone                  the time zone for of the \n     *                                  <code>DailyCalendar</code> which will \n     *                                  also be used to resolve the given \n     *                                  start/end times.                                 \n     * @param rangeStartingTimeInMillis a long representing the starting time \n     *                                  for the time range\n     * @param rangeEndingTimeInMillis   a long representing the ending time for\n     *                                  the time range\n     */\n    public DailyCalendar(TimeZone timeZone,\n                         long rangeStartingTimeInMillis,\n                         long rangeEndingTimeInMillis) {\n        super(timeZone);\n        setTimeRange(rangeStartingTimeInMillis, \n                     rangeEndingTimeInMillis);\n    }\n\n    /**\n     * Create a <CODE>DailyCalendar</CODE> with a time range defined by the\n     * specified values and the specified <CODE>baseCalendar</CODE>. The values\n     * are subject to the following considerations:\n     * <UL><LI>Only the time-of-day portion of the specified values will be\n     *         used</LI>\n     *     <LI>The starting time must be before the ending time of the defined\n     *         time range. Note this means that a time range may not cross\n     *         daily boundaries (10PM - 2AM). <I>(because only time value are\n     *         are used, it is possible for the two values to represent a valid\n     *         time range and <CODE>rangeStartingTime &gt; \n     *         rangeEndingTime</CODE>)</I></LI>  \n     * </UL> \n     * \n     * @param baseCalendar              the base calendar for this calendar\n     *                                  instance &ndash; see {@link \n     *                                  BaseCalendar} for more information on \n     *                                  base calendar functionality\n     * @param timeZone                  the time zone for of the \n     *                                  <code>DailyCalendar</code> which will \n     *                                  also be used to resolve the given \n     *                                  start/end times.                                 \n     * @param rangeStartingTimeInMillis a long representing the starting time \n     *                                  for the time range\n     * @param rangeEndingTimeInMillis   a long representing the ending time for\n     *                                  the time range\n     */\n    public DailyCalendar(org.quartz.Calendar baseCalendar,\n                         TimeZone timeZone,\n                         long rangeStartingTimeInMillis,\n                         long rangeEndingTimeInMillis) {\n        super(baseCalendar, timeZone);\n        setTimeRange(rangeStartingTimeInMillis,\n                     rangeEndingTimeInMillis);\n    }\n\n    @Override\n    public Object clone() {\n        return (DailyCalendar) super.clone();\n    }\n    \n    /**\n     * Determines whether the given time (in milliseconds) is 'included' by the\n     * <CODE>BaseCalendar</CODE>\n     * \n     * @param timeInMillis the date/time to test\n     * @return a boolean indicating whether the specified time is 'included' by\n     *         the <CODE>BaseCalendar</CODE>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeInMillis) {        \n        if ((getBaseCalendar() != null) && \n                (!getBaseCalendar().isTimeIncluded(timeInMillis))) {\n            return false;\n        }\n        \n        long startOfDayInMillis = getStartOfDayJavaCalendar(timeInMillis).getTime().getTime();\n        long endOfDayInMillis = getEndOfDayJavaCalendar(timeInMillis).getTime().getTime();\n        long timeRangeStartingTimeInMillis = \n            getTimeRangeStartingTimeInMillis(timeInMillis);\n        long timeRangeEndingTimeInMillis = \n            getTimeRangeEndingTimeInMillis(timeInMillis);\n        if (!invertTimeRange) {\n            return \n                ((timeInMillis > startOfDayInMillis && \n                    timeInMillis < timeRangeStartingTimeInMillis) ||\n                (timeInMillis > timeRangeEndingTimeInMillis && \n                    timeInMillis < endOfDayInMillis));\n        } else {\n            return ((timeInMillis >= timeRangeStartingTimeInMillis) &&\n                    (timeInMillis <= timeRangeEndingTimeInMillis));\n        }\n    }\n\n    /**\n     * Determines the next time included by the <CODE>DailyCalendar</CODE>\n     * after the specified time.\n     * \n     * @param timeInMillis the initial date/time after which to find an \n     *                     included time\n     * @return the time in milliseconds representing the next time included\n     *         after the specified time.\n     */\n    @Override\n    public long getNextIncludedTime(long timeInMillis) {\n        long nextIncludedTime = timeInMillis + oneMillis;\n        \n        while (!isTimeIncluded(nextIncludedTime)) {\n            if (!invertTimeRange) {\n                //If the time is in a range excluded by this calendar, we can\n                // move to the end of the excluded time range and continue \n                // testing from there. Otherwise, if nextIncludedTime is \n                // excluded by the baseCalendar, ask it the next time it \n                // includes and begin testing from there. Failing this, add one\n                // millisecond and continue testing.\n                if ((nextIncludedTime >= \n                        getTimeRangeStartingTimeInMillis(nextIncludedTime)) && \n                    (nextIncludedTime <= \n                        getTimeRangeEndingTimeInMillis(nextIncludedTime))) {\n                    \n                    nextIncludedTime = \n                        getTimeRangeEndingTimeInMillis(nextIncludedTime) + \n                            oneMillis;\n                } else if ((getBaseCalendar() != null) && \n                        (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){\n                    nextIncludedTime = \n                        getBaseCalendar().getNextIncludedTime(nextIncludedTime);\n                } else {\n                    nextIncludedTime++;\n                }\n            } else {\n                //If the time is in a range excluded by this calendar, we can\n                // move to the end of the excluded time range and continue \n                // testing from there. Otherwise, if nextIncludedTime is \n                // excluded by the baseCalendar, ask it the next time it \n                // includes and begin testing from there. Failing this, add one\n                // millisecond and continue testing.\n                if (nextIncludedTime < \n                        getTimeRangeStartingTimeInMillis(nextIncludedTime)) {\n                    nextIncludedTime = \n                        getTimeRangeStartingTimeInMillis(nextIncludedTime);\n                } else if (nextIncludedTime > \n                        getTimeRangeEndingTimeInMillis(nextIncludedTime)) {\n                    //(move to start of next day)\n                    nextIncludedTime = getEndOfDayJavaCalendar(nextIncludedTime).getTime().getTime();\n                    nextIncludedTime += 1L;\n                } else if ((getBaseCalendar() != null) && \n                        (!getBaseCalendar().isTimeIncluded(nextIncludedTime))){\n                    nextIncludedTime = \n                        getBaseCalendar().getNextIncludedTime(nextIncludedTime);\n                } else {\n                    nextIncludedTime++;\n                }\n            }\n        }\n        \n        return nextIncludedTime;\n    }\n\n    /**\n     * Returns the start time of the time range (in milliseconds) of the day \n     * specified in <CODE>timeInMillis</CODE>\n     * \n     * @param timeInMillis a time containing the desired date for the starting\n     *                     time of the time range.\n     * @return a date/time (in milliseconds) representing the start time of the\n     *         time range for the specified date.\n     */\n    public long getTimeRangeStartingTimeInMillis(long timeInMillis) {\n        Calendar rangeStartingTime = createJavaCalendar(timeInMillis);\n        rangeStartingTime.set(Calendar.HOUR_OF_DAY, rangeStartingHourOfDay);\n        rangeStartingTime.set(Calendar.MINUTE, rangeStartingMinute);\n        rangeStartingTime.set(Calendar.SECOND, rangeStartingSecond);\n        rangeStartingTime.set(Calendar.MILLISECOND, rangeStartingMillis);\n        return rangeStartingTime.getTime().getTime();\n    }\n\n    /**\n     * Returns the end time of the time range (in milliseconds) of the day\n     * specified in <CODE>timeInMillis</CODE>\n     * \n     * @param timeInMillis a time containing the desired date for the ending\n     *                     time of the time range.\n     * @return a date/time (in milliseconds) representing the end time of the\n     *         time range for the specified date.\n     */\n    public long getTimeRangeEndingTimeInMillis(long timeInMillis) {\n        Calendar rangeEndingTime = createJavaCalendar(timeInMillis);\n        rangeEndingTime.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay);\n        rangeEndingTime.set(Calendar.MINUTE, rangeEndingMinute);\n        rangeEndingTime.set(Calendar.SECOND, rangeEndingSecond);\n        rangeEndingTime.set(Calendar.MILLISECOND, rangeEndingMillis);\n        return rangeEndingTime.getTime().getTime();\n    }\n\n    /**\n     * Indicates whether the time range represents an inverted time range (see\n     * class description).\n     * \n     * @return a boolean indicating whether the time range is inverted\n     */\n    public boolean getInvertTimeRange() {\n        return invertTimeRange;\n    }\n    \n    /**\n     * Indicates whether the time range represents an inverted time range (see\n     * class description).\n     * \n     * @param flag the new value for the <CODE>invertTimeRange</CODE> flag.\n     */\n    public void setInvertTimeRange(boolean flag) {\n        this.invertTimeRange = flag;\n    }\n    \n    /**\n     * Returns a string representing the properties of the \n     * <CODE>DailyCalendar</CODE>\n     * \n     * @return the properties of the DailyCalendar in a String format\n     */\n    @Override\n    public String toString() {\n        NumberFormat numberFormatter = NumberFormat.getNumberInstance();\n        numberFormatter.setMaximumFractionDigits(0);\n        numberFormatter.setMinimumIntegerDigits(2);\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"base calendar: [\");\n        if (getBaseCalendar() != null) {\n            buffer.append(getBaseCalendar().toString());\n        } else {\n            buffer.append(\"null\");\n        }\n        buffer.append(\"], time range: '\");\n        buffer.append(numberFormatter.format(rangeStartingHourOfDay));\n        buffer.append(\":\");\n        buffer.append(numberFormatter.format(rangeStartingMinute));\n        buffer.append(\":\");\n        buffer.append(numberFormatter.format(rangeStartingSecond));\n        buffer.append(\":\");\n        numberFormatter.setMinimumIntegerDigits(3);\n        buffer.append(numberFormatter.format(rangeStartingMillis));\n        numberFormatter.setMinimumIntegerDigits(2);\n        buffer.append(\" - \");\n        buffer.append(numberFormatter.format(rangeEndingHourOfDay));\n        buffer.append(\":\");\n        buffer.append(numberFormatter.format(rangeEndingMinute));\n        buffer.append(\":\");\n        buffer.append(numberFormatter.format(rangeEndingSecond));\n        buffer.append(\":\");\n        numberFormatter.setMinimumIntegerDigits(3);\n        buffer.append(numberFormatter.format(rangeEndingMillis));\n        buffer.append(\"', inverted: \").append(invertTimeRange).append(\"]\");\n        return buffer.toString();\n    }\n    \n    /**\n     * Helper method to split the given string by the given delimiter.\n     */\n    private String[] split(String string, String delim) {\n        ArrayList<String> result = new ArrayList<>();\n        \n        StringTokenizer stringTokenizer = new StringTokenizer(string, delim);\n        while (stringTokenizer.hasMoreTokens()) {\n            result.add(stringTokenizer.nextToken());\n        }\n        \n        return (String[])result.toArray(new String[result.size()]);\n    }\n    \n    /**\n     * Sets the time range for the <CODE>DailyCalendar</CODE> to the times \n     * represented in the specified Strings. \n     * \n     * @param rangeStartingTimeString a String representing the start time of \n     *                                the time range\n     * @param rangeEndingTimeString   a String representing the end time of the\n     *                                excluded time range\n     */\n    public void setTimeRange(String rangeStartingTimeString,\n                              String rangeEndingTimeString) {\n        String[] rangeStartingTime;\n        int rStartingHourOfDay;\n        int rStartingMinute;\n        int rStartingSecond;\n        int rStartingMillis;\n        \n        String[] rEndingTime;\n        int rEndingHourOfDay;\n        int rEndingMinute;\n        int rEndingSecond;\n        int rEndingMillis;\n        \n        rangeStartingTime = split(rangeStartingTimeString, colon);\n        \n        if ((rangeStartingTime.length < 2) || (rangeStartingTime.length > 4)) {\n            throw new IllegalArgumentException(\"Invalid time string '\" + \n                    rangeStartingTimeString + \"'\");\n        }\n        \n        rStartingHourOfDay = Integer.parseInt(rangeStartingTime[0]);\n        rStartingMinute = Integer.parseInt(rangeStartingTime[1]);\n        if (rangeStartingTime.length > 2) {\n            rStartingSecond = Integer.parseInt(rangeStartingTime[2]);\n        } else {\n            rStartingSecond = 0;\n        }\n        if (rangeStartingTime.length == 4) {\n            rStartingMillis = Integer.parseInt(rangeStartingTime[3]);\n        } else {\n            rStartingMillis = 0;\n        }\n        \n        rEndingTime = split(rangeEndingTimeString, colon);\n\n        if ((rEndingTime.length < 2) || (rEndingTime.length > 4)) {\n            throw new IllegalArgumentException(\"Invalid time string '\" + \n                    rangeEndingTimeString + \"'\");\n        }\n        \n        rEndingHourOfDay = Integer.parseInt(rEndingTime[0]);\n        rEndingMinute = Integer.parseInt(rEndingTime[1]);\n        if (rEndingTime.length > 2) {\n            rEndingSecond = Integer.parseInt(rEndingTime[2]);\n        } else {\n            rEndingSecond = 0;\n        }\n        if (rEndingTime.length == 4) {\n            rEndingMillis = Integer.parseInt(rEndingTime[3]);\n        } else {\n            rEndingMillis = 0;\n        }\n        \n        setTimeRange(rStartingHourOfDay,\n                     rStartingMinute,\n                     rStartingSecond,\n                     rStartingMillis,\n                     rEndingHourOfDay,\n                     rEndingMinute,\n                     rEndingSecond,\n                     rEndingMillis);\n    }\n\n    /**\n     * Sets the time range for the <CODE>DailyCalendar</CODE> to the times\n     * represented in the specified values.  \n     * \n     * @param rangeStartingHourOfDay the hour of the start of the time range\n     * @param rangeStartingMinute    the minute of the start of the time range\n     * @param rangeStartingSecond    the second of the start of the time range\n     * @param rangeStartingMillis    the millisecond of the start of the time\n     *                               range\n     * @param rangeEndingHourOfDay   the hour of the end of the time range\n     * @param rangeEndingMinute      the minute of the end of the time range\n     * @param rangeEndingSecond      the second of the end of the time range\n     * @param rangeEndingMillis      the millisecond of the start of the time \n     *                               range\n     */\n    public void setTimeRange(int rangeStartingHourOfDay,\n                              int rangeStartingMinute,\n                              int rangeStartingSecond,\n                              int rangeStartingMillis,\n                              int rangeEndingHourOfDay,\n                              int rangeEndingMinute,\n                              int rangeEndingSecond,\n                              int rangeEndingMillis) {\n        validate(rangeStartingHourOfDay,\n                 rangeStartingMinute,\n                 rangeStartingSecond,\n                 rangeStartingMillis);\n        \n        validate(rangeEndingHourOfDay,\n                 rangeEndingMinute,\n                 rangeEndingSecond,\n                 rangeEndingMillis);\n        \n        Calendar startCal = createJavaCalendar();\n        startCal.set(Calendar.HOUR_OF_DAY, rangeStartingHourOfDay);\n        startCal.set(Calendar.MINUTE, rangeStartingMinute);\n        startCal.set(Calendar.SECOND, rangeStartingSecond);\n        startCal.set(Calendar.MILLISECOND, rangeStartingMillis);\n        \n        Calendar endCal = createJavaCalendar();\n        endCal.set(Calendar.HOUR_OF_DAY, rangeEndingHourOfDay);\n        endCal.set(Calendar.MINUTE, rangeEndingMinute);\n        endCal.set(Calendar.SECOND, rangeEndingSecond);\n        endCal.set(Calendar.MILLISECOND, rangeEndingMillis);\n        \n        if (!startCal.before(endCal)) {\n            throw new IllegalArgumentException(invalidTimeRange +\n                    rangeStartingHourOfDay + \":\" +\n                    rangeStartingMinute + \":\" +\n                    rangeStartingSecond + \":\" +\n                    rangeStartingMillis + separator +\n                    rangeEndingHourOfDay + \":\" +\n                    rangeEndingMinute + \":\" +\n                    rangeEndingSecond + \":\" +\n                    rangeEndingMillis);\n        }\n        \n        this.rangeStartingHourOfDay = rangeStartingHourOfDay;\n        this.rangeStartingMinute = rangeStartingMinute;\n        this.rangeStartingSecond = rangeStartingSecond;\n        this.rangeStartingMillis = rangeStartingMillis;\n        this.rangeEndingHourOfDay = rangeEndingHourOfDay;\n        this.rangeEndingMinute = rangeEndingMinute;\n        this.rangeEndingSecond = rangeEndingSecond;\n        this.rangeEndingMillis = rangeEndingMillis;\n    }\n    \n    /**\n     * Sets the time range for the <CODE>DailyCalendar</CODE> to the times\n     * represented in the specified <CODE>java.util.Calendar</CODE>s. \n     * \n     * @param rangeStartingCalendar a Calendar containing the start time for\n     *                              the <CODE>DailyCalendar</CODE>\n     * @param rangeEndingCalendar   a Calendar containing the end time for\n     *                              the <CODE>DailyCalendar</CODE>\n     */\n    public void setTimeRange(Calendar rangeStartingCalendar,\n                              Calendar rangeEndingCalendar) {\n        setTimeRange(\n                rangeStartingCalendar.get(Calendar.HOUR_OF_DAY),\n                rangeStartingCalendar.get(Calendar.MINUTE),\n                rangeStartingCalendar.get(Calendar.SECOND),\n                rangeStartingCalendar.get(Calendar.MILLISECOND),\n                rangeEndingCalendar.get(Calendar.HOUR_OF_DAY),\n                rangeEndingCalendar.get(Calendar.MINUTE),\n                rangeEndingCalendar.get(Calendar.SECOND),\n                rangeEndingCalendar.get(Calendar.MILLISECOND));\n    }\n    \n    /**\n     * Sets the time range for the <CODE>DailyCalendar</CODE> to the times\n     * represented in the specified values. \n     * \n     * @param rangeStartingTime the starting time (in milliseconds) for the\n     *                          time range\n     * @param rangeEndingTime   the ending time (in milliseconds) for the time\n     *                          range\n     */\n    public void setTimeRange(long rangeStartingTime, \n                              long rangeEndingTime) {\n        setTimeRange(\n            createJavaCalendar(rangeStartingTime), \n            createJavaCalendar(rangeEndingTime));\n    }\n    \n    /**\n     * Checks the specified values for validity as a set of time values.\n     * \n     * @param hourOfDay the hour of the time to check (in military (24-hour)\n     *                  time)\n     * @param minute    the minute of the time to check\n     * @param second    the second of the time to check\n     * @param millis    the millisecond of the time to check\n     */\n    private void validate(int hourOfDay, int minute, int second, int millis) {\n        if (hourOfDay < 0 || hourOfDay > 23) {\n            throw new IllegalArgumentException(invalidHourOfDay + hourOfDay);\n        }\n        if (minute < 0 || minute > 59) {\n            throw new IllegalArgumentException(invalidMinute + minute);\n        }\n        if (second < 0 || second > 59) {\n            throw new IllegalArgumentException(invalidSecond + second);\n        }\n        if (millis < 0 || millis > 999) {\n            throw new IllegalArgumentException(invalidMillis + millis);\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/HolidayCalendar.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.calendar;\n\nimport java.io.Serializable;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.SortedSet;\nimport java.util.TimeZone;\nimport java.util.TreeSet;\n\nimport org.quartz.Calendar;\n\n/**\n * <p>\n * This implementation of the Calendar stores a list of holidays (full days\n * that are excluded from scheduling).\n * </p>\n * \n * <p>\n * The implementation DOES take the year into consideration, so if you want to\n * exclude July 4th for the next 10 years, you need to add 10 entries to the\n * exclude list.\n * </p>\n * \n * @author Sharada Jambula\n * @author Juergen Donnerstag\n */\npublic class HolidayCalendar extends BaseCalendar implements Calendar,\n        Serializable {\n    private static final long serialVersionUID = -7590908752291814693L;\n    \n    // A sorted set to store the holidays\n    private TreeSet<Date> dates = new TreeSet<>();\n\n    public HolidayCalendar() {\n    }\n\n    public HolidayCalendar(Calendar baseCalendar) {\n        super(baseCalendar);\n    }\n\n    public HolidayCalendar(TimeZone timeZone) {\n        super(timeZone);\n    }\n\n    public HolidayCalendar(Calendar baseCalendar, TimeZone timeZone) {\n        super(baseCalendar, timeZone);\n    }\n\n    @Override\n    public Object clone() {\n        HolidayCalendar clone = (HolidayCalendar) super.clone();\n        clone.dates = new TreeSet<>(dates);\n        return clone;\n    }\n    \n    /**\n     * <p>\n     * Determine whether the given time (in milliseconds) is 'included' by the\n     * Calendar.\n     * </p>\n     * \n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeStamp) {\n        if (!super.isTimeIncluded(timeStamp)) {\n            return false;\n        }\n\n        Date lookFor = getStartOfDayJavaCalendar(timeStamp).getTime();\n\n        return !(dates.contains(lookFor));\n    }\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time.\n     * </p>\n     * \n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public long getNextIncludedTime(long timeStamp) {\n\n        // Call base calendar implementation first\n        long baseTime = super.getNextIncludedTime(timeStamp);\n        if ((baseTime > 0) && (baseTime > timeStamp)) {\n            timeStamp = baseTime;\n        }\n\n        // Get timestamp for 00:00:00\n        java.util.Calendar day = getStartOfDayJavaCalendar(timeStamp);\n        while (!isTimeIncluded(day.getTime().getTime())) {\n            day.add(java.util.Calendar.DATE, 1);\n        }\n\n        return day.getTime().getTime();\n    }\n\n    /**\n     * <p>\n     * Add the given Date to the list of excluded days. Only the month, day and\n     * year of the returned dates are significant.\n     * </p>\n     */\n    public void addExcludedDate(Date excludedDate) {\n        Date date = getStartOfDayJavaCalendar(excludedDate.getTime()).getTime();\n        /*\n         * System.err.println( \"HolidayCalendar.add(): date=\" +\n         * excludedDate.toLocaleString());\n         */\n        this.dates.add(date);\n    }\n\n    public void removeExcludedDate(Date dateToRemove) {\n        Date date = getStartOfDayJavaCalendar(dateToRemove.getTime()).getTime();\n        dates.remove(date);\n    }\n\n    /**\n     * <p>\n     * Returns a <code>SortedSet</code> of Dates representing the excluded\n     * days. Only the month, day and year of the returned dates are\n     * significant.\n     * </p>\n     */\n    public SortedSet<Date> getExcludedDates() {\n        return Collections.unmodifiableSortedSet(dates);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/MonthlyCalendar.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.impl.calendar;\n\nimport java.io.Serializable;\nimport java.util.TimeZone;\n\nimport org.quartz.Calendar;\n\n/**\n * <p>\n * This implementation of the Calendar excludes a set of days of the month. You\n * may use it to exclude every first day of each month for example. But you may define\n * any day of a month.\n * </p>\n *\n * @see org.quartz.Calendar\n * @see org.quartz.impl.calendar.BaseCalendar\n *\n * @author Juergen Donnerstag\n */\npublic class MonthlyCalendar extends BaseCalendar implements Calendar,\n        Serializable {\n\n    private static final long serialVersionUID = 419164961091807944L;\n\n    private static final int MAX_DAYS_IN_MONTH = 31;\n\n    // An array to store a months days which are to be excluded.\n    // java.util.Calendar.get( ) as index.\n    private boolean[] excludeDays = new boolean[MAX_DAYS_IN_MONTH];\n\n    // Will be set to true, if all week days are excluded\n    private boolean excludeAll = false;\n\n    public MonthlyCalendar() {\n        this(null, null);\n    }\n\n    public MonthlyCalendar(Calendar baseCalendar) {\n        this(baseCalendar, null);\n    }\n\n    public MonthlyCalendar(TimeZone timeZone) {\n        this(null, timeZone);\n    }\n\n    public MonthlyCalendar(Calendar baseCalendar, TimeZone timeZone) {\n        super(baseCalendar, timeZone);\n\n        // all days are included by default\n        excludeAll = areAllDaysExcluded();\n    }\n\n    @Override\n    public Object clone() {\n        MonthlyCalendar clone = (MonthlyCalendar) super.clone();\n        clone.excludeDays = excludeDays.clone();\n        return clone;\n    }\n\n    /**\n     * <p>\n     * Get the array which defines the exclude-value of each day of month.\n     * Only the first 31 elements of the array are relevant, with the 0 index\n     * element representing the first day of the month.\n     * </p>\n     */\n    public boolean[] getDaysExcluded() {\n        return excludeDays;\n    }\n\n    /**\n     * <p>\n     * Return true, if day is defined to be excluded.\n     * </p>\n     *\n     * @param day The day of the month (from 1 to 31) to check.\n     */\n    public boolean isDayExcluded(int day) {\n        if ((day < 1) || (day > MAX_DAYS_IN_MONTH)) {\n            throw new IllegalArgumentException(\n                \"The day parameter must be in the range of 1 to \" + MAX_DAYS_IN_MONTH);\n        }\n\n        return excludeDays[day - 1];\n    }\n\n    /**\n     * <p>\n     * Redefine the array of days excluded. The array must non-null and of size\n     * greater or equal to 31. The 0 index element represents the first day of\n     * the month.\n     * </p>\n     */\n    public void setDaysExcluded(boolean[] days) {\n        if (days == null) {\n            throw new IllegalArgumentException(\"The days parameter cannot be null.\");\n        }\n\n        if (days.length < MAX_DAYS_IN_MONTH) {\n            throw new IllegalArgumentException(\n                \"The days parameter must have a length of at least \" + MAX_DAYS_IN_MONTH + \" elements.\");\n        }\n\n        excludeDays = days;\n        excludeAll = areAllDaysExcluded();\n    }\n\n    /**\n     * <p>\n     * Redefine a certain day of the month to be excluded (true) or included\n     * (false).\n     * </p>\n     *\n     * @param day The day of the month (from 1 to 31) to set.\n     */\n    public void setDayExcluded(int day, boolean exclude) {\n        if ((day < 1) || (day > MAX_DAYS_IN_MONTH)) {\n            throw new IllegalArgumentException(\n                \"The day parameter must be in the range of 1 to \" + MAX_DAYS_IN_MONTH);\n        }\n\n        excludeDays[day - 1] = exclude;\n        excludeAll = areAllDaysExcluded();\n    }\n\n    /**\n     * <p>\n     * Check if all days are excluded. That is no day is included.\n     * </p>\n     */\n    public boolean areAllDaysExcluded() {\n        for (int i = 1; i <= MAX_DAYS_IN_MONTH; i++) {\n            if (!isDayExcluded(i)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * <p>\n     * Determine whether the given time (in milliseconds) is 'included' by the\n     * Calendar.\n     * </p>\n     *\n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeStamp) {\n        if (excludeAll) {\n            return false;\n        }\n\n        // Test the base calendar first. Only if the base calendar not already\n        // excludes the time/date, continue evaluating this calendar instance.\n        if (!super.isTimeIncluded(timeStamp)) { return false; }\n\n        java.util.Calendar cl = createJavaCalendar(timeStamp);\n        int day = cl.get(java.util.Calendar.DAY_OF_MONTH);\n\n        return !(isDayExcluded(day));\n    }\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time. Return the original value if timeStamp is\n     * included. Return 0 if all days are excluded.\n     * </p>\n     *\n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public long getNextIncludedTime(long timeStamp) {\n        if (excludeAll) {\n            return 0;\n        }\n\n        // Call base calendar implementation first\n        long baseTime = super.getNextIncludedTime(timeStamp);\n        if ((baseTime > 0) && (baseTime > timeStamp)) {\n            timeStamp = baseTime;\n        }\n\n        // Get timestamp for 00:00:00\n        java.util.Calendar cl = getStartOfDayJavaCalendar(timeStamp);\n        int day = cl.get(java.util.Calendar.DAY_OF_MONTH);\n\n        if (!isDayExcluded(day)) {\n            return timeStamp; // return the original value\n        }\n\n        while (isDayExcluded(day)) {\n            cl.add(java.util.Calendar.DATE, 1);\n            day = cl.get(java.util.Calendar.DAY_OF_MONTH);\n        }\n\n        return cl.getTime().getTime();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/calendar/WeeklyCalendar.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.impl.calendar;\n\nimport java.io.Serializable;\nimport java.util.TimeZone;\n\nimport org.quartz.Calendar;\n\n/**\n * <p>\n * This implementation of the Calendar excludes a set of days of the week. You\n * may use it to exclude weekends for example. But you may define any day of\n * the week.  By default it excludes SATURDAY and SUNDAY.\n * </p>\n *\n * @see org.quartz.Calendar\n * @see org.quartz.impl.calendar.BaseCalendar\n *\n * @author Juergen Donnerstag\n */\npublic class WeeklyCalendar extends BaseCalendar implements Calendar,\n        Serializable {\n    private static final long serialVersionUID = -6809298821229007586L;\n\n    // An array to store the week days which are to be excluded.\n    // java.util.Calendar.MONDAY etc. are used as index.\n    private boolean[] excludeDays = new boolean[8];\n\n    // Will be set to true, if all week days are excluded\n    private boolean excludeAll = false;\n\n    public WeeklyCalendar() {\n        this(null, null);\n    }\n\n    public WeeklyCalendar(Calendar baseCalendar) {\n        this(baseCalendar, null);\n    }\n\n    public WeeklyCalendar(TimeZone timeZone) {\n        super(null, timeZone);\n    }\n\n    public WeeklyCalendar(Calendar baseCalendar, TimeZone timeZone) {\n        super(baseCalendar, timeZone);\n\n        excludeDays[java.util.Calendar.SUNDAY] = true;\n        excludeDays[java.util.Calendar.SATURDAY] = true;\n        excludeAll = areAllDaysExcluded();\n    }\n\n    @Override\n    public Object clone() {\n        WeeklyCalendar clone = (WeeklyCalendar) super.clone();\n        clone.excludeDays = excludeDays.clone();\n        return clone;\n    }\n\n    /**\n     * <p>\n     * Get the array with the week days\n     * </p>\n     */\n    public boolean[] getDaysExcluded() {\n        return excludeDays;\n    }\n\n    /**\n     * <p>\n     * Return true, if wday (see Calendar.get()) is defined to be excluded. E. g.\n     * saturday and sunday.\n     * </p>\n     */\n    public boolean isDayExcluded(int wday) {\n        return excludeDays[wday];\n    }\n\n    /**\n     * <p>\n     * Redefine the array of days excluded. The array must of size greater or\n     * equal 8. java.util.Calendar's constants like MONDAY should be used as\n     * index. A value of true is regarded as: exclude it.\n     * </p>\n     */\n    public void setDaysExcluded(boolean[] weekDays) {\n        if (weekDays == null) {\n            return;\n        }\n\n        excludeDays = weekDays;\n        excludeAll = areAllDaysExcluded();\n    }\n\n    /**\n     * <p>\n     * Redefine a certain day of the week to be excluded (true) or included\n     * (false). Use java.util.Calendar's constants like MONDAY to determine the\n     * wday.\n     * </p>\n     */\n    public void setDayExcluded(int wday, boolean exclude) {\n        excludeDays[wday] = exclude;\n        excludeAll = areAllDaysExcluded();\n    }\n\n    /**\n     * <p>\n     * Check if all week days are excluded. That is no day is included.\n     * </p>\n     *\n     * @return boolean\n     */\n    public boolean areAllDaysExcluded() {\n        return\n            isDayExcluded(java.util.Calendar.SUNDAY) &&\n            isDayExcluded(java.util.Calendar.MONDAY) &&\n            isDayExcluded(java.util.Calendar.TUESDAY) &&\n            isDayExcluded(java.util.Calendar.WEDNESDAY) &&\n            isDayExcluded(java.util.Calendar.THURSDAY) &&\n            isDayExcluded(java.util.Calendar.FRIDAY) &&\n            isDayExcluded(java.util.Calendar.SATURDAY);\n    }\n\n    /**\n     * <p>\n     * Determine whether the given time (in milliseconds) is 'included' by the\n     * Calendar.\n     * </p>\n     *\n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public boolean isTimeIncluded(long timeStamp) {\n        if (excludeAll) {\n            return false;\n        }\n\n        // Test the base calendar first. Only if the base calendar not already\n        // excludes the time/date, continue evaluating this calendar instance.\n        if (!super.isTimeIncluded(timeStamp)) { return false; }\n\n        java.util.Calendar cl = createJavaCalendar(timeStamp);\n        int wday = cl.get(java.util.Calendar.DAY_OF_WEEK);\n\n        return !(isDayExcluded(wday));\n    }\n\n    /**\n     * <p>\n     * Determine the next time (in milliseconds) that is 'included' by the\n     * Calendar after the given time. Return the original value if timeStamp is\n     * included. Return 0 if all days are excluded.\n     * </p>\n     *\n     * <p>\n     * Note that this Calendar is only has full-day precision.\n     * </p>\n     */\n    @Override\n    public long getNextIncludedTime(long timeStamp) {\n        if (excludeAll) {\n            return 0;\n        }\n\n        // Call base calendar implementation first\n        long baseTime = super.getNextIncludedTime(timeStamp);\n        if ((baseTime > 0) && (baseTime > timeStamp)) {\n            timeStamp = baseTime;\n        }\n\n        // Get timestamp for 00:00:00\n        java.util.Calendar cl = getStartOfDayJavaCalendar(timeStamp);\n        int wday = cl.get(java.util.Calendar.DAY_OF_WEEK);\n\n        if (!isDayExcluded(wday)) {\n            return timeStamp; // return the original value\n        }\n\n        while (isDayExcluded(wday)) {\n            cl.add(java.util.Calendar.DATE, 1);\n            wday = cl.get(java.util.Calendar.DAY_OF_WEEK);\n        }\n\n        return cl.getTime().getTime();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/AttributeRestoringConnectionInvocationHandler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * Protects a <code>{@link java.sql.Connection}</code>'s attributes from being permanently modified.\n * </p>\n * \n * <p>\n * Wraps a provided <code>{@link java.sql.Connection}</code> such that its auto \n * commit and transaction isolation attributes can be overwritten, but \n * will automatically restored to their original values when the connection\n * is actually closed (and potentially returned to a pool for reuse).\n * </p>\n * \n * @see org.quartz.impl.jdbcjobstore.JobStoreSupport#getConnection()\n * @see org.quartz.impl.jdbcjobstore.JobStoreCMT#getNonManagedTXConnection()\n */\npublic class AttributeRestoringConnectionInvocationHandler implements InvocationHandler {\n    private final Connection conn;\n    \n    private boolean overwroteOriginalAutoCommitValue;\n    private boolean overwroteOriginalTxIsolationValue;\n\n    // Set if overwroteOriginalAutoCommitValue is true\n    private boolean originalAutoCommitValue; \n\n    // Set if overwroteOriginalTxIsolationValue is true\n    private int originalTxIsolationValue;\n    \n    public AttributeRestoringConnectionInvocationHandler(\n        Connection conn) {\n        this.conn = conn;\n    }\n\n    protected Logger getLog() {\n        return LoggerFactory.getLogger(getClass());\n    }\n    \n    public Object invoke(Object proxy, Method method, Object[] args)\n        throws Throwable {\n        switch (method.getName()) {\n            case \"setAutoCommit\":\n                setAutoCommit((Boolean) args[0]);\n                break;\n            case \"setTransactionIsolation\":\n                setTransactionIsolation((Integer) args[0]);\n                break;\n            case \"close\":\n                close();\n                break;\n            default:\n                try {\n                    return method.invoke(conn, args);\n                } catch (InvocationTargetException ite) {\n                    throw (ite.getCause() != null ? ite.getCause() : ite);\n                }\n\n        }\n        \n        return null;\n    }\n     \n    /**\n     * Sets this connection's auto-commit mode to the given state, saving\n     * the original mode.  The connection's original auto commit mode is restored\n     * when the connection is closed.\n     */\n    public void setAutoCommit(boolean autoCommit) throws SQLException {\n        boolean currentAutoCommitValue = conn.getAutoCommit();\n            \n        if (autoCommit != currentAutoCommitValue) {\n            if (!overwroteOriginalAutoCommitValue) {\n                overwroteOriginalAutoCommitValue = true;\n                originalAutoCommitValue = currentAutoCommitValue;\n            }\n            \n            conn.setAutoCommit(autoCommit);\n        }\n    }\n\n    /**\n     * Attempts to change the transaction isolation level to the given level, saving\n     * the original level.  The connection's original transaction isolation level is \n     * restored when the connection is closed.\n     */\n    public void setTransactionIsolation(int level) throws SQLException {\n        int currentLevel = conn.getTransactionIsolation();\n        \n        if (level != currentLevel) {\n            if (!overwroteOriginalTxIsolationValue) {\n                overwroteOriginalTxIsolationValue = true;\n                originalTxIsolationValue = currentLevel;\n            }\n            \n            conn.setTransactionIsolation(level);\n        }\n    }\n    \n    /**\n     * Gets the underlying connection to which all operations ultimately \n     * defer.  This is provided in case a user ever needs to punch through \n     * the wrapper to access vendor specific methods outside of the \n     * standard <code>java.sql.Connection</code> interface.\n     * \n     * @return The underlying connection to which all operations\n     * ultimately defer.\n     */\n    public Connection getWrappedConnection() {\n        return conn;\n    }\n\n    /**\n     * Attempts to restore the auto commit and transaction isolation connection\n     * attributes of the wrapped connection to their original values (if they\n     * were overwritten).\n     */\n    public void restoreOriginalAttributes() {\n        try {\n            if (overwroteOriginalAutoCommitValue) {\n                conn.setAutoCommit(originalAutoCommitValue);\n            }\n        } catch (Throwable t) {\n            getLog().warn(\"Failed restore connection's original auto commit setting.\", t);\n        }\n        \n        try {    \n            if (overwroteOriginalTxIsolationValue) {\n                conn.setTransactionIsolation(originalTxIsolationValue);\n            }\n        } catch (Throwable t) {\n            getLog().warn(\"Failed restore connection's original transaction isolation setting.\", t);\n        }\n    }\n    \n    /**\n     * Attempts to restore the auto commit and transaction isolation connection\n     * attributes of the wrapped connection to their original values (if they\n     * were overwritten), before finally actually closing the wrapped connection.\n     */\n    public void close() throws SQLException {\n        restoreOriginalAttributes();\n        \n        conn.close();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/CUBRIDDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport com.mchange.v2.c3p0.C3P0ProxyConnection;\nimport java.io.*;\nimport java.lang.reflect.Method;\nimport java.sql.*;\n\n/**\n * <p> This is a driver delegate for the CUBRID JDBC driver. For Quartz 2.x </p>\n * Blob handling instructions at\n * http://www.cubrid.org/manual/831/en/Using%20BLOB|CLOB Also at\n * http://www.cubrid.org/wiki_tutorials/entry/working-with-cubrid-blob-clob-data-types\n *\n * @author Timothy Anyona\n */\npublic class CUBRIDDelegate extends StdJDBCDelegate {\n\n    /**\n     * <p> This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard JDBC\n     * <code>java.sql.Blob</code> operations. </p>\n     *\n     * @param rs the result set, already queued to the correct row\n     * @param colName the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException if a class found during deserialization\n     * cannot be found\n     * @throws IOException if deserialization causes an error\n     */\n    @Override\n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n            throws ClassNotFoundException, IOException, SQLException {\n\n        Object obj = null;\n        InputStream binaryInput;\n\n        Blob blob = rs.getBlob(colName);\n        byte[] bytes = blob.getBytes(1, (int) blob.length());\n\n        if (bytes != null && bytes.length != 0) {\n            binaryInput = new ByteArrayInputStream(bytes);\n\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n        }\n\n        return obj;\n    }\n\n    @Override\n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n            throws ClassNotFoundException, IOException, SQLException {\n\n        if (canUseProperties()) {\n            InputStream binaryInput;\n\n            Blob blob = rs.getBlob(colName);\n            byte[] bytes = blob.getBytes(1, (int) blob.length());\n\n            if (bytes == null || bytes.length == 0) {\n                return null;\n            }\n            binaryInput = new ByteArrayInputStream(bytes);\n            return binaryInput;\n        }\n\n        return getObjectFromBlob(rs, colName);\n    }\n\n    /**\n     * Sets the designated parameter to the byte array of the given\n     * <code>ByteArrayOutputStream</code>. Will set parameter value to null if\n     * the\n     * <code>ByteArrayOutputStream</code> is null. This just wraps\n     * <code>{@link PreparedStatement#setBytes(int, byte[])}</code> by default,\n     * but it can be overloaded by subclass delegates for databases that don't\n     * explicitly support storing bytes in this way.\n     */\n    @Override\n    protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos)\n            throws SQLException {\n        \n        byte[] byteArray;\n        if (baos == null) {\n            //saving 0 byte blob may cause error? like http://dev.naver.com/projects/cubrid/issue/13710 - (0 byte bit)\n            //alternatively store null since blob not null columns are not allowed (cubrid 8.4.1). may be allowed in future versions?\n            byteArray = new byte[0];\n        } else {\n            byteArray = baos.toByteArray();\n        }\n\n        //quartz 2.x uses c3p0, c3p0 doesn't support createBlob method as of 0.9.2        \n        Connection conn = ps.getConnection();\n        if (conn instanceof C3P0ProxyConnection) {\n            try {\n                C3P0ProxyConnection c3p0Conn = (C3P0ProxyConnection) conn;\n                Method m = Connection.class.getMethod(\"createBlob\", new Class[]{}); //will call createBlob method on the underlying connection\n                Object[] args = new Object[]{}; //arguments to be passed to the method. none in this case\n                Blob blob = (Blob) c3p0Conn.rawConnectionOperation(m, C3P0ProxyConnection.RAW_CONNECTION, args); \n                blob.setBytes(1, byteArray);\n                ps.setBlob(index, blob);\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n        } else {\n            Blob blob = ps.getConnection().createBlob();\n            blob.setBytes(1, byteArray);\n            ps.setBlob(index, blob);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/CacheDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.Blob;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for InterSystems Caché database.\n * </p>\n * \n * <p>\n * Works with the Oracle table creation scripts / schema.\n * </p>\n * \n * @author Franck Routier\n * @author <a href=\"mailto:alci@mecadu.org\">Franck Routier</a>\n */\npublic class CacheDelegate extends StdJDBCDelegate {\n        \n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n  \n    /**\n     * Sets the designated parameter to the byte array of the given\n     * <code>ByteArrayOutputStream</code>. Will set parameter value to null if the\n     * <code>ByteArrayOutputStream</code> is null.\n     * This just wraps <code>{@link PreparedStatement#setBytes(int, byte[])}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support storing bytes in this way.\n     */\n    @Override\n    protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException {\n        ps.setObject(index, ((baos == null) ? null : baos.toByteArray()), java.sql.Types.BLOB);\n    } \n\n    /**\n     * {@inheritDoc}\n     * <p>\n     * Caché requires {@code java.sql.Blob} instances to be explicitly freed.\n     */\n    @Override\n    protected Object getObjectFromBlob(ResultSet rs, String colName) throws ClassNotFoundException, IOException, SQLException {\n        Blob blob = rs.getBlob(colName);\n        if (blob == null) {\n            return null;\n        } else {\n            try {\n                if (blob.length() == 0) {\n                    return null;\n                } else {\n                    InputStream binaryInput = blob.getBinaryStream();\n                    if (binaryInput == null) {\n                        return null;\n                    } else if (binaryInput instanceof ByteArrayInputStream && ((ByteArrayInputStream) binaryInput).available() == 0 ) {\n                        return null;\n                    } else {\n                        try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                            return in.readObject();\n                        }\n                    }\n                }\n            } finally {\n                blob.free();\n            }\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     * <p>\n     * Caché requires {@code java.sql.Blob} instances to be explicitly freed.\n     */\n    @Override\n    protected Object getJobDataFromBlob(ResultSet rs, String colName) throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            Blob blob = rs.getBlob(colName);\n            if (blob == null) {\n                return null;\n            } else {\n                return new BlobFreeingStream(blob, blob.getBinaryStream());\n            }\n        } else {\n            return getObjectFromBlob(rs, colName);\n        }\n    }\n    \n    private static class BlobFreeingStream extends InputStream {\n        \n        private final Blob source;\n        private final InputStream delegate;\n\n        private BlobFreeingStream(Blob blob, InputStream stream) {\n            this.source = blob;\n            this.delegate = stream;\n        }\n\n        @Override\n        public int read() throws IOException {\n            return delegate.read();\n        }\n\n        @Override\n        public int read(byte[] b) throws IOException {\n            return delegate.read(b);\n        }\n\n        @Override\n        public int read(byte[] b, int off, int len) throws IOException {\n            return delegate.read(b, off, len);\n        }\n\n        @Override\n        public long skip(long n) throws IOException {\n            return delegate.skip(n);\n        }\n\n        @Override\n        public int available() throws IOException {\n            return delegate.available();\n        }\n\n        @Override\n        public void close() throws IOException {\n            try {\n                delegate.close();\n            } finally {\n                try {\n                    source.free();\n                } catch (SQLException ex) {\n                    throw new IOException(ex);\n                }\n            }\n        }\n\n        @Override\n        public synchronized void mark(int readlimit) {\n            delegate.mark(readlimit);\n        }\n\n        @Override\n        public synchronized void reset() throws IOException {\n            delegate.reset();\n        }\n\n        @Override\n        public boolean markSupported() {\n            return delegate.markSupported();\n        }\n    }\n}\n\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/CalendarIntervalTriggerPersistenceDelegate.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.util.TimeZone;\n\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.triggers.CalendarIntervalTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\npublic class CalendarIntervalTriggerPersistenceDelegate extends SimplePropertiesTriggerPersistenceDelegateSupport {\n\n    public boolean canHandleTriggerType(OperableTrigger trigger) {\n        return ((trigger instanceof CalendarIntervalTriggerImpl) && !((CalendarIntervalTriggerImpl)trigger).hasAdditionalProperties());\n    }\n\n    public String getHandledTriggerTypeDiscriminator() {\n        return TTYPE_CAL_INT;\n    }\n\n    @Override\n    protected SimplePropertiesTriggerProperties getTriggerProperties(OperableTrigger trigger) {\n\n        CalendarIntervalTriggerImpl calTrig = (CalendarIntervalTriggerImpl)trigger;\n        \n        SimplePropertiesTriggerProperties props = new SimplePropertiesTriggerProperties();\n        \n        props.setInt1(calTrig.getRepeatInterval());\n        props.setString1(calTrig.getRepeatIntervalUnit().name());\n        props.setInt2(calTrig.getTimesTriggered());\n        props.setString2(calTrig.getTimeZone().getID());\n        props.setBoolean1(calTrig.isPreserveHourOfDayAcrossDaylightSavings());\n        props.setBoolean2(calTrig.isSkipDayIfHourDoesNotExist());\n        \n        return props;\n    }\n\n    @Override\n    protected TriggerPropertyBundle getTriggerPropertyBundle(SimplePropertiesTriggerProperties props) {\n\n        TimeZone tz = null; // if we use null, that's ok as system default tz will be used\n        String tzId = props.getString2();\n        if(tzId != null && !tzId.trim().isEmpty()) // there could be null entries from previously released versions\n            tz = TimeZone.getTimeZone(tzId);\n        \n        ScheduleBuilder<?> sb = CalendarIntervalScheduleBuilder.calendarIntervalSchedule()\n            .withInterval(props.getInt1(), IntervalUnit.valueOf(props.getString1()))\n            .inTimeZone(tz)\n            .preserveHourOfDayAcrossDaylightSavings(props.isBoolean1())\n            .skipDayIfHourDoesNotExist(props.isBoolean2());\n        \n        int timesTriggered = props.getInt2();\n        \n        String[] statePropertyNames = { \"timesTriggered\" };\n        Object[] statePropertyValues = { timesTriggered };\n\n        return new TriggerPropertyBundle(sb, statePropertyNames, statePropertyValues);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/Constants.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\n/**\n * <p>\n * This interface can be implemented by any <code>{@link\n * org.quartz.impl.jdbcjobstore.DriverDelegate}</code>\n * class that needs to use the constants contained herein.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n */\npublic interface Constants {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    // Table names\n    String TABLE_JOB_DETAILS = \"JOB_DETAILS\";\n\n    String TABLE_TRIGGERS = \"TRIGGERS\";\n\n    String TABLE_SIMPLE_TRIGGERS = \"SIMPLE_TRIGGERS\";\n\n    String TABLE_CRON_TRIGGERS = \"CRON_TRIGGERS\";\n\n    String TABLE_BLOB_TRIGGERS = \"BLOB_TRIGGERS\";\n\n    String TABLE_FIRED_TRIGGERS = \"FIRED_TRIGGERS\";\n\n    String TABLE_CALENDARS = \"CALENDARS\";\n\n    String TABLE_PAUSED_TRIGGERS = \"PAUSED_TRIGGER_GRPS\";\n\n    String TABLE_LOCKS = \"LOCKS\";\n\n    String TABLE_SCHEDULER_STATE = \"SCHEDULER_STATE\";\n\n    // TABLE_JOB_DETAILS columns names\n    \n    String COL_SCHEDULER_NAME = \"SCHED_NAME\";\n    \n    String COL_JOB_NAME = \"JOB_NAME\";\n\n    String COL_JOB_GROUP = \"JOB_GROUP\";\n\n    String COL_IS_DURABLE = \"IS_DURABLE\";\n\n    String COL_IS_VOLATILE = \"IS_VOLATILE\";\n\n    String COL_IS_NONCONCURRENT = \"IS_NONCONCURRENT\";\n\n    String COL_IS_UPDATE_DATA = \"IS_UPDATE_DATA\";\n\n    String COL_REQUESTS_RECOVERY = \"REQUESTS_RECOVERY\";\n\n    String COL_JOB_DATAMAP = \"JOB_DATA\";\n\n    String COL_JOB_CLASS = \"JOB_CLASS_NAME\";\n\n    String COL_DESCRIPTION = \"DESCRIPTION\";\n\n    // TABLE_TRIGGERS columns names\n    String COL_TRIGGER_NAME = \"TRIGGER_NAME\";\n\n    String COL_TRIGGER_GROUP = \"TRIGGER_GROUP\";\n\n    String COL_NEXT_FIRE_TIME = \"NEXT_FIRE_TIME\";\n\n    String COL_PREV_FIRE_TIME = \"PREV_FIRE_TIME\";\n\n    String COL_TRIGGER_STATE = \"TRIGGER_STATE\";\n\n    String COL_TRIGGER_TYPE = \"TRIGGER_TYPE\";\n\n    String COL_START_TIME = \"START_TIME\";\n\n    String COL_END_TIME = \"END_TIME\";\n\n    String COL_PRIORITY = \"PRIORITY\";\n\n    String COL_MISFIRE_INSTRUCTION = \"MISFIRE_INSTR\";\n\n    String ALIAS_COL_NEXT_FIRE_TIME = \"ALIAS_NXT_FR_TM\";\n\n    // TABLE_SIMPLE_TRIGGERS columns names\n    String COL_REPEAT_COUNT = \"REPEAT_COUNT\";\n\n    String COL_REPEAT_INTERVAL = \"REPEAT_INTERVAL\";\n\n    String COL_TIMES_TRIGGERED = \"TIMES_TRIGGERED\";\n\n    // TABLE_CRON_TRIGGERS columns names\n    String COL_CRON_EXPRESSION = \"CRON_EXPRESSION\";\n\n    // TABLE_BLOB_TRIGGERS columns names\n    String COL_BLOB = \"BLOB_DATA\";\n\n    String COL_TIME_ZONE_ID = \"TIME_ZONE_ID\";\n\n    // TABLE_FIRED_TRIGGERS columns names\n    String COL_INSTANCE_NAME = \"INSTANCE_NAME\";\n\n    String COL_FIRED_TIME = \"FIRED_TIME\";\n\n    String COL_SCHED_TIME = \"SCHED_TIME\";\n    \n    String COL_ENTRY_ID = \"ENTRY_ID\";\n\n    String COL_ENTRY_STATE = \"STATE\";\n\n    // TABLE_CALENDARS columns names\n    String COL_CALENDAR_NAME = \"CALENDAR_NAME\";\n\n    String COL_CALENDAR = \"CALENDAR\";\n\n    // TABLE_LOCKS columns names\n    String COL_LOCK_NAME = \"LOCK_NAME\";\n\n    // TABLE_LOCKS columns names\n    String COL_LAST_CHECKIN_TIME = \"LAST_CHECKIN_TIME\";\n\n    String COL_CHECKIN_INTERVAL = \"CHECKIN_INTERVAL\";\n\n    // MISC CONSTANTS\n    String DEFAULT_TABLE_PREFIX = \"QRTZ_\";\n\n    // STATES\n    String STATE_WAITING = \"WAITING\";\n\n    String STATE_ACQUIRED = \"ACQUIRED\";\n\n    String STATE_EXECUTING = \"EXECUTING\";\n\n    String STATE_COMPLETE = \"COMPLETE\";\n\n    String STATE_BLOCKED = \"BLOCKED\";\n\n    String STATE_ERROR = \"ERROR\";\n\n    String STATE_PAUSED = \"PAUSED\";\n\n    String STATE_PAUSED_BLOCKED = \"PAUSED_BLOCKED\";\n\n    String STATE_DELETED = \"DELETED\";\n\n    /**\n     * @deprecated Whether a trigger has misfired is no longer a state, but \n     * rather now identified dynamically by whether the trigger's next fire \n     * time is more than the misfire threshold time in the past.\n     */\n    @Deprecated\n    String STATE_MISFIRED = \"MISFIRED\";\n\n    String ALL_GROUPS_PAUSED = \"_$_ALL_GROUPS_PAUSED_$_\";\n\n    // TRIGGER TYPES\n    /** Simple Trigger type. */\n    String TTYPE_SIMPLE = \"SIMPLE\";\n\n    /** Cron Trigger type. */\n    String TTYPE_CRON = \"CRON\";\n\n    /** Calendar Interval Trigger type. */\n    String TTYPE_CAL_INT = \"CAL_INT\";\n\n    /** Daily Time Interval Trigger type. */\n    String TTYPE_DAILY_TIME_INT = \"DAILY_I\";\n\n    /** A general blob Trigger type. */\n    String TTYPE_BLOB = \"BLOB\";\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/CronTriggerPersistenceDelegate.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.TimeZone;\n\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDetail;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\npublic class CronTriggerPersistenceDelegate implements TriggerPersistenceDelegate, StdJDBCConstants {\n\n    protected String tablePrefix;\n    protected String schedNameLiteral;\n\n    public void initialize(String theTablePrefix, String schedName) {\n        this.tablePrefix = theTablePrefix;\n        this.schedNameLiteral = \"'\" + schedName + \"'\";\n    }\n\n    public String getHandledTriggerTypeDiscriminator() {\n        return TTYPE_CRON;\n    }\n\n    public boolean canHandleTriggerType(OperableTrigger trigger) {\n        return ((trigger instanceof CronTriggerImpl) && !((CronTriggerImpl)trigger).hasAdditionalProperties());\n    }\n\n    public int deleteExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(DELETE_CRON_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public int insertExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        CronTrigger cronTrigger = (CronTrigger)trigger;\n        \n        PreparedStatement ps = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(INSERT_CRON_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setString(3, cronTrigger.getCronExpression());\n            ps.setString(4, cronTrigger.getTimeZone().getID());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public TriggerPropertyBundle loadExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(SELECT_CRON_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n            if (rs.next()) {\n                return loadExtendedTriggerPropertiesFromResultSet(rs, triggerKey);\n            }\n\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, Util.rtp(SELECT_CRON_TRIGGER, tablePrefix, schedNameLiteral));\n\n        } finally {\n            Util.closeResultSet(rs);\n            Util.closeStatement(ps);\n        }\n    }\n\n\n    public TriggerPropertyBundle loadExtendedTriggerPropertiesFromResultSet(ResultSet rs, TriggerKey triggerKey) throws SQLException {\n        if (Util.areNull(rs, COL_CRON_EXPRESSION, COL_TIME_ZONE_ID)) {\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, this.getClass());\n        }\n        String cronExpr = rs.getString(COL_CRON_EXPRESSION);\n        String timeZoneId = rs.getString(COL_TIME_ZONE_ID);\n\n        CronScheduleBuilder cb = CronScheduleBuilder.cronSchedule(cronExpr);\n\n        if (timeZoneId != null)\n            cb.inTimeZone(TimeZone.getTimeZone(timeZoneId));\n\n        return new TriggerPropertyBundle(cb, null, null);\n    }\n\n    public boolean hasInlinedResultSetProperties() {\n        return true;\n    }\n\n    public int updateExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        CronTrigger cronTrigger = (CronTrigger)trigger;\n        \n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(UPDATE_CRON_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, cronTrigger.getCronExpression());\n            ps.setString(2, cronTrigger.getTimeZone().getID());\n            ps.setString(3, trigger.getKey().getName());\n            ps.setString(4, trigger.getKey().getGroup());\n            \n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DB2v6Delegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.JobKey;\n\n/**\n * Quartz JDBC delegate for DB2 v6 databases. <code>select count(name)</code>\n * had to be replaced with <code>select count(*)</code>.\n * \n * @author Martin Renner\n * @author James House\n */\npublic class DB2v6Delegate extends StdJDBCDelegate {\n    @SuppressWarnings(\"hiding\")\n    public static final String SELECT_NUM_JOBS = \"SELECT COUNT(*) FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    @SuppressWarnings(\"hiding\")\n    public static final String SELECT_NUM_TRIGGERS_FOR_JOB = \"SELECT COUNT(*) FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" \n            + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    @SuppressWarnings(\"hiding\")\n    public static final String SELECT_NUM_TRIGGERS = \"SELECT COUNT(*) FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    @SuppressWarnings(\"hiding\")\n    public static final String SELECT_NUM_CALENDARS = \"SELECT COUNT(*) FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    @Override\n    public int selectNumJobs(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_JOBS));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    @Override           \n    public int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS_FOR_JOB));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return rs.getInt(1);\n            } else {\n                return 0;\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    @Override\n    public int selectNumTriggers(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    @Override           \n    public int selectNumCalendars(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_CALENDARS));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DB2v7Delegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayOutputStream;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n/**\n * Quartz JDBC delegate for DB2 v7 databases.\n * <p>\n * This differs from the <code>StdJDBCDelegate</code> in that it stores \n * <code>boolean</code> values in an <code>varchar(1)</code> column, and saves \n * serialized data in a byte array using \n * <code>{@link PreparedStatement#setObject(int, java.lang.Object, int)}</code> \n * rather than <code>{@link PreparedStatement#setBytes(int, byte[])}</code>.\n * </p>\n * \n * @author Blair Jensen\n */\npublic class DB2v7Delegate extends StdJDBCDelegate {\n\n    /**\n     * Sets the designated parameter to the byte array of the given\n     * <code>ByteArrayOutputStream</code>.  Will set parameter value to null if the \n     * <code>ByteArrayOutputStream</code> is null.\n     * Wraps <code>{@link PreparedStatement#setObject(int, java.lang.Object, int)}</code> rather than\n     * <code>{@link PreparedStatement#setBytes(int, byte[])}</code> as required by the \n     * DB2 v7 database.\n     */\n    @Override           \n    protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException {\n        ps.setObject(index, ((baos == null) ? null : baos.toByteArray()), java.sql.Types.BLOB);\n    }\n\n    /**\n     * Sets the designated parameter to the given Java <code>boolean</code> value.\n     * This translates the boolean to 1/0 for true/false.\n     */\n    @Override           \n    protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException {\n        ps.setString(index, ((val) ? \"1\" : \"0\"));\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DB2v8Delegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n/**\n * Quartz JDBC delegate for DB2 v8 databases.\n * <p>\n * This differs from the <code>StdJDBCDelegate</code> in that it stores \n * <code>boolean</code> values in an <code>integer</code> column.\n * </p>\n * \n * @author Blair Jensen\n */\npublic class DB2v8Delegate extends StdJDBCDelegate {\n\n    /**\n     * Sets the designated parameter to the given Java <code>boolean</code> value.\n     * This translates the boolean to 1/0 for true/false.\n     */\n    @Override           \n    protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException {\n        ps.setInt(index, ((val) ? 1 : 0));\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DBSemaphore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.util.HashSet;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Base class for database based lock handlers for providing thread/resource locking \n * in order to protect resources from being altered by multiple threads at the \n * same time.\n */\npublic abstract class DBSemaphore implements Semaphore, Constants,\n    StdJDBCConstants, TablePrefixAware {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    final ThreadLocal<HashSet<String>> lockOwners = new ThreadLocal<>();\n\n    private String sql;\n    private String insertSql;\n\n    private String tablePrefix;\n    \n    private String schedName;\n\n    private String expandedSQL;\n    private String expandedInsertSQL;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public DBSemaphore(String tablePrefix, String schedName, String defaultSQL, String defaultInsertSQL) {\n        this.tablePrefix = tablePrefix;\n        this.schedName = schedName;\n        setSQL(defaultSQL);\n        setInsertSQL(defaultInsertSQL);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    private HashSet<String> getThreadLocks() {\n        HashSet<String> threadLocks = lockOwners.get();\n        if (threadLocks == null) {\n            threadLocks = new HashSet<>();\n            lockOwners.set(threadLocks);\n        }\n        return threadLocks;\n    }\n\n    /**\n     * Execute the SQL that will lock the proper database row.\n     */\n    protected abstract void executeSQL(Connection conn, String lockName, String theExpandedSQL, String theExpandedInsertSQL) \n        throws LockException;\n    \n    /**\n     * Grants a lock on the identified resource to the calling thread (blocking\n     * until it is available).\n     * \n     * @return true if the lock was obtained.\n     */\n    public boolean obtainLock(Connection conn, String lockName)\n        throws LockException {\n\n        if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' is desired by: {}\", lockName, Thread.currentThread().getName());\n        }\n        if (!isLockOwner(lockName)) {\n\n            executeSQL(conn, lockName, expandedSQL, expandedInsertSQL);\n            \n            if(log.isDebugEnabled()) {\n                log.debug(\"Lock '{}' given to: {}\", lockName, Thread.currentThread().getName());\n            }\n            getThreadLocks().add(lockName);\n            //getThreadLocksObtainer().put(lockName, new\n            // Exception(\"Obtainer...\"));\n        } else if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' Is already owned by: {}\", lockName, Thread.currentThread().getName());\n        }\n\n        return true;\n    }\n\n       \n    /**\n     * Release the lock on the identified resource if it is held by the calling\n     * thread.\n     */\n    public void releaseLock(String lockName) {\n\n        if (isLockOwner(lockName)) {\n            if(getLog().isDebugEnabled()) {\n                getLog().debug(\"Lock '{}' returned by: {}\", lockName, Thread.currentThread().getName());\n            }\n            getThreadLocks().remove(lockName);\n            //getThreadLocksObtainer().remove(lockName);\n        } else if (getLog().isDebugEnabled()) {\n            getLog().warn(\"Lock '{}' attempt to return by: {} -- but not owner!\", lockName, Thread.currentThread().getName(), new Exception(\"stack-trace of wrongful returner\"));\n        }\n    }\n\n    /**\n     * Determine whether the calling thread owns a lock on the identified\n     * resource.\n     */\n    public boolean isLockOwner(String lockName) {\n        return getThreadLocks().contains(lockName);\n    }\n\n    /**\n     * This Semaphore implementation does use the database.\n     */\n    public boolean requiresConnection() {\n        return true;\n    }\n\n    protected String getSQL() {\n        return sql;\n    }\n\n    protected void setSQL(String sql) {\n        if ((sql != null) && (!sql.trim().isEmpty())) {\n            this.sql = sql.trim();\n        }\n        \n        setExpandedSQL();\n    }\n\n    protected void setInsertSQL(String insertSql) {\n        if ((insertSql != null) && (!insertSql.trim().isEmpty())) {\n            this.insertSql = insertSql.trim();\n        }\n        \n        setExpandedSQL();\n    }\n\n    private void setExpandedSQL() {\n        if (getTablePrefix() != null && getSchedName() != null && sql != null && insertSql != null) {\n            expandedSQL = Util.rtp(this.sql, getTablePrefix(), getSchedulerNameLiteral());\n            expandedInsertSQL = Util.rtp(this.insertSql, getTablePrefix(), getSchedulerNameLiteral());\n        }\n    }\n    \n    private String schedNameLiteral = null;\n    protected String getSchedulerNameLiteral() {\n        if(schedNameLiteral == null)\n            schedNameLiteral = \"'\" + schedName + \"'\";\n        return schedNameLiteral;\n    }\n\n    public String getSchedName() {\n        return schedName;\n    }\n\n    public void setSchedName(String schedName) {\n        this.schedName = schedName;\n        \n        setExpandedSQL();\n    }\n    \n    protected String getTablePrefix() {\n        return tablePrefix;\n    }\n\n    public void setTablePrefix(String tablePrefix) {\n        this.tablePrefix = tablePrefix;\n        \n        setExpandedSQL();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DailyTimeIntervalTriggerPersistenceDelegate.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Set;\n\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\nimport org.quartz.DailyTimeIntervalTrigger;\nimport org.quartz.TimeOfDay;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.triggers.DailyTimeIntervalTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * Persist a DailyTimeIntervalTrigger by converting internal fields to and from\n * SimplePropertiesTriggerProperties.\n * \n * @see DailyTimeIntervalScheduleBuilder\n * @see DailyTimeIntervalTrigger\n * \n * @since 2.1.0\n * \n * @author Zemian Deng &lt;saltnlight5@gmail.com&gt;\n */\npublic class DailyTimeIntervalTriggerPersistenceDelegate extends SimplePropertiesTriggerPersistenceDelegateSupport {\n\n    public boolean canHandleTriggerType(OperableTrigger trigger) {\n        return ((trigger instanceof DailyTimeIntervalTrigger) && !((DailyTimeIntervalTriggerImpl)trigger).hasAdditionalProperties());\n    }\n\n    public String getHandledTriggerTypeDiscriminator() {\n        return TTYPE_DAILY_TIME_INT;\n    }\n\n    @Override\n    protected SimplePropertiesTriggerProperties getTriggerProperties(OperableTrigger trigger) {\n        DailyTimeIntervalTriggerImpl dailyTrigger = (DailyTimeIntervalTriggerImpl)trigger;\n        SimplePropertiesTriggerProperties props = new SimplePropertiesTriggerProperties();\n        \n        props.setInt1(dailyTrigger.getRepeatInterval());\n        props.setString1(dailyTrigger.getRepeatIntervalUnit().name());\n        props.setInt2(dailyTrigger.getTimesTriggered());\n        \n        Set<Integer> days = dailyTrigger.getDaysOfWeek();\n        String daysStr = join(days, \",\");\n        props.setString2(daysStr);\n\n        StringBuilder timeOfDayBuffer = new StringBuilder();\n        TimeOfDay startTimeOfDay = dailyTrigger.getStartTimeOfDay();\n        if (startTimeOfDay != null) {\n            timeOfDayBuffer.append(startTimeOfDay.getHour()).append(\",\");\n            timeOfDayBuffer.append(startTimeOfDay.getMinute()).append(\",\");\n            timeOfDayBuffer.append(startTimeOfDay.getSecond()).append(\",\");\n        } else {\n            timeOfDayBuffer.append(\",,,\");\n        }\n        TimeOfDay endTimeOfDay = dailyTrigger.getEndTimeOfDay();\n        if (endTimeOfDay != null) {\n            timeOfDayBuffer.append(endTimeOfDay.getHour()).append(\",\");\n            timeOfDayBuffer.append(endTimeOfDay.getMinute()).append(\",\");\n            timeOfDayBuffer.append(endTimeOfDay.getSecond());\n        } else {\n            timeOfDayBuffer.append(\",,,\");\n        }\n        props.setString3(timeOfDayBuffer.toString());\n        \n        props.setLong1(dailyTrigger.getRepeatCount());\n        \n        return props;\n    }\n\n    private String join(Set<Integer> days, String sep) {\n        StringBuilder sb = new StringBuilder();\n        if (days == null || days.size() <= 0)\n            return \"\";\n        \n        Iterator<Integer> itr = days.iterator();\n        sb.append(itr.next());\n        while(itr.hasNext()) {\n            sb.append(sep).append(itr.next());\n        }\n        return sb.toString();\n    }\n\n    @Override\n    protected TriggerPropertyBundle getTriggerPropertyBundle(SimplePropertiesTriggerProperties props) {\n        int repeatCount = (int)props.getLong1();\n        int interval = props.getInt1();\n        String intervalUnitStr = props.getString1();\n        String daysOfWeekStr = props.getString2();\n        String timeOfDayStr = props.getString3();\n\n        IntervalUnit intervalUnit = IntervalUnit.valueOf(intervalUnitStr);\n        DailyTimeIntervalScheduleBuilder scheduleBuilder = DailyTimeIntervalScheduleBuilder\n                .dailyTimeIntervalSchedule()\n                .withInterval(interval, intervalUnit)\n                .withRepeatCount(repeatCount);\n                \n        if (daysOfWeekStr != null) {\n            Set<Integer> daysOfWeek = new HashSet<>();\n            String[] nums = daysOfWeekStr.split(\",\");\n            if (nums.length > 0) {\n                for (String num : nums) {\n                    daysOfWeek.add(Integer.parseInt(num));\n                }\n                scheduleBuilder.onDaysOfTheWeek(daysOfWeek);\n            }\n        } else {\n            scheduleBuilder.onDaysOfTheWeek(DailyTimeIntervalScheduleBuilder.ALL_DAYS_OF_THE_WEEK);\n        }\n        \n        if (timeOfDayStr != null) {\n            String[] nums = timeOfDayStr.split(\",\");\n            TimeOfDay startTimeOfDay;\n            if (nums.length >= 3) {\n                int hour = Integer.parseInt(nums[0]);\n                int min = Integer.parseInt(nums[1]);\n                int sec = Integer.parseInt(nums[2]);\n                startTimeOfDay = new TimeOfDay(hour, min, sec);\n            } else {\n                startTimeOfDay = TimeOfDay.hourMinuteAndSecondOfDay(0, 0, 0);\n            }\n            scheduleBuilder.startingDailyAt(startTimeOfDay);\n\n            TimeOfDay endTimeOfDay;\n            if (nums.length >= 6) {\n                int hour = Integer.parseInt(nums[3]);\n                int min = Integer.parseInt(nums[4]);\n                int sec = Integer.parseInt(nums[5]);\n                endTimeOfDay = new TimeOfDay(hour, min, sec);\n            } else {\n                endTimeOfDay = TimeOfDay.hourMinuteAndSecondOfDay(23, 59, 59);\n            }\n            scheduleBuilder.endingDailyAt(endTimeOfDay);\n        } else {\n            scheduleBuilder.startingDailyAt(TimeOfDay.hourMinuteAndSecondOfDay(0, 0, 0));\n            scheduleBuilder.endingDailyAt(TimeOfDay.hourMinuteAndSecondOfDay(23, 59, 59));\n        }\n        \n        int timesTriggered = props.getInt2();\n        String[] statePropertyNames = { \"timesTriggered\" };\n        Object[] statePropertyValues = { timesTriggered };\n\n        return new TriggerPropertyBundle(scheduleBuilder, statePropertyNames, statePropertyValues);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/DriverDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.utils.Key;\nimport org.slf4j.Logger;\n\n/**\n * <p>\n * This is the base interface for all driver delegate classes.\n * </p>\n * \n * <p>\n * This interface is very similar to the <code>{@link\n * org.quartz.spi.JobStore}</code>\n * interface except each method has an additional <code>{@link java.sql.Connection}</code>\n * parameter.\n * </p>\n * \n * <p>\n * Unless a database driver has some <strong>extremely-DB-specific</strong>\n * requirements, any DriverDelegate implementation classes should extend the\n * <code>{@link org.quartz.impl.jdbcjobstore.StdJDBCDelegate}</code> class.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n */\npublic interface DriverDelegate {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * @param initString of the format: settingName=settingValue|otherSettingName=otherSettingValue|...\n     * @throws NoSuchDelegateException\n     */\n    void initialize(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper, boolean useProperties, String initString) throws NoSuchDelegateException;\n\n    //---------------------------------------------------------------------------\n    // startup / recovery\n    //---------------------------------------------------------------------------\n    /**\n     * <p>\n     * Update all triggers having one of the two given states, to the given new\n     * state.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param newState\n     *          the new state for the triggers\n     * @param oldState1\n     *          the first old state to update\n     * @param oldState2\n     *          the second old state to update\n     * @return number of rows updated\n     */\n    int updateTriggerStatesFromOtherStates(Connection conn,\n        String newState, String oldState1, String oldState2)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Get the names of all of the triggers that have misfired - according to\n     * the given timestamp.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    List<TriggerKey> selectMisfiredTriggers(Connection conn, long ts)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Get the names of all of the triggers in the given state that have\n     * misfired - according to the given timestamp.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    List<TriggerKey> selectMisfiredTriggersInState(Connection conn, String state,\n        long ts) throws SQLException;\n    \n    /**\n     * <p>\n     * Get the names of all of the triggers in the given states that have\n     * misfired - according to the given timestamp.  No more than count will\n     * be returned.\n     * </p>\n     * \n     * @param conn the DB Connection\n     * @param count the most misfired triggers to return, negative for all\n     * @param resultList Output parameter.  A List of \n     *      <code>{@link org.quartz.utils.Key}</code> objects.  Must not be null.\n     *          \n     * @return Whether there are more misfired triggers left to find beyond\n     *         the given count.\n     */\n    boolean hasMisfiredTriggersInState(Connection conn, String state1, \n        long ts, int count, List<TriggerKey> resultList) throws SQLException;\n    \n    /**\n     * <p>\n     * Get the number of triggers in the given state that have\n     * misfired - according to the given timestamp.\n     * </p>\n     * \n     * @param conn the DB Connection\n     */\n    int countMisfiredTriggersInState(\n        Connection conn, String state1, long ts) throws SQLException;\n\n    /**\n     * <p>\n     * Get the names of all of the triggers in the given group and state that\n     * have misfired - according to the given timestamp.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    List<TriggerKey> selectMisfiredTriggersInGroupInState(Connection conn,\n        String groupName, String state, long ts) throws SQLException;\n    \n\n    /**\n     * <p>\n     * Select all of the triggers for jobs that are requesting recovery. The\n     * returned trigger objects will have unique \"recoverXXX\" trigger names and\n     * will be in the <code>{@link\n     * org.quartz.Scheduler}.DEFAULT_RECOVERY_GROUP</code>\n     * trigger group.\n     * </p>\n     * \n     * <p>\n     * In order to preserve the ordering of the triggers, the fire time will be\n     * set from the <code>COL_FIRED_TIME</code> column in the <code>TABLE_FIRED_TRIGGERS</code>\n     * table. The caller is responsible for calling <code>computeFirstFireTime</code>\n     * on each returned trigger. It is also up to the caller to insert the\n     * returned triggers to ensure that they are fired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link org.quartz.Trigger}</code> objects\n     */\n    List<OperableTrigger> selectTriggersForRecoveringJobs(Connection conn)\n        throws SQLException, IOException, ClassNotFoundException;\n\n    /**\n     * <p>\n     * Delete all fired triggers.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    int deleteFiredTriggers(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Delete all fired triggers of the given instance.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    int deleteFiredTriggers(Connection conn, String instanceId)\n        throws SQLException;\n\n    //---------------------------------------------------------------------------\n    // jobs\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to insert\n     * @return number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    int insertJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException;\n\n    /**\n     * <p>\n     * Update the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    int updateJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException;\n\n    /**\n     * <p>\n     * Get the names of all of the triggers associated with the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    List<TriggerKey> selectTriggerKeysForJob(Connection conn, JobKey jobKey) throws SQLException;\n\n    /**\n     * <p>\n     * Delete the job detail record for the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the number of rows deleted\n     */\n    int deleteJobDetail(Connection conn, JobKey jobKey)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Check whether or not the given job disallows concurrent execution.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return true if the job exists and disallows concurrent execution, false otherwise\n     */\n    boolean isJobNonConcurrent(Connection conn, JobKey jobKey) throws SQLException;\n\n    /**\n     * <p>\n     * Check whether or not the given job exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return true if the job exists, false otherwise\n     */\n    boolean jobExists(Connection conn, JobKey jobKey)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Update the job data map for the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return the number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    int updateJobData(Connection conn, JobDetail job)\n        throws IOException, SQLException;\n\n    /**\n     * <p>\n     * Select the JobDetail object for a given job name / group name.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the populated JobDetail object\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found or if\n     *           the job class could not be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    JobDetail selectJobDetail(Connection conn, JobKey jobKey,\n        ClassLoadHelper loadHelper)\n        throws ClassNotFoundException, IOException, SQLException;\n\n    /**\n     * <p>\n     * Select all the JobDetail object for a given job name / group name.\n     * </p>\n     *\n     * @param conn\n     *          the DB Connection\n     * @param matcher\n     *          the group matcher to evaluate against the known jobs\n     * @return A list of populated JobDetail objects\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found or if\n     *           the job class could not be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    List<JobDetail> selectJobDetails(Connection conn, GroupMatcher<JobKey> matcher,\n         ClassLoadHelper loadHelper)\n        throws ClassNotFoundException, IOException, SQLException;\n\n    /**\n     * <p>\n     * Select the total number of jobs stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of jobs stored\n     */\n    int selectNumJobs(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the job group names that are stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> group names\n     */\n    List<String> selectJobGroups(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the jobs contained in a given group.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param matcher\n     *          the group matcher to evaluate against the known jobs\n     * @return an array of <code>String</code> job names\n     */\n    Set<JobKey> selectJobsInGroup(Connection conn, GroupMatcher<JobKey> matcher)\n        throws SQLException;\n\n    //---------------------------------------------------------------------------\n    // triggers\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the base trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    int insertTrigger(Connection conn, OperableTrigger trigger, String state,\n        JobDetail jobDetail) throws SQLException, IOException;\n\n    /**\n     * <p>\n     * Update the base trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows updated\n     */\n    int updateTrigger(Connection conn, OperableTrigger trigger, String state,\n        JobDetail jobDetail) throws SQLException, IOException;\n\n    /**\n     * <p>\n     * Check whether or not a trigger exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the number of rows updated\n     */\n    boolean triggerExists(Connection conn, TriggerKey triggerKey) throws SQLException;\n\n    /**\n     * <p>\n     * Update the state for a given trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @param state\n     *          the new state for the trigger\n     * @return the number of rows updated\n     */\n    int updateTriggerState(Connection conn, TriggerKey triggerKey,\n        String state) throws SQLException;\n\n    /**\n     * <p>\n     * Update the given trigger to the given new state, if it is in the given\n     * old state.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * \n     * @param newState\n     *          the new state for the trigger\n     * @param oldState\n     *          the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    int updateTriggerStateFromOtherState(Connection conn,\n        TriggerKey triggerKey, String newState, String oldState) throws SQLException;\n\n    /**\n     * <p>\n     * Update the given trigger to the given new state, if it is one of the\n     * given old states.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * \n     * @param newState\n     *          the new state for the trigger\n     * @param oldState1\n     *          one of the old state the trigger must be in\n     * @param oldState2\n     *          one of the old state the trigger must be in\n     * @param oldState3\n     *          one of the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    int updateTriggerStateFromOtherStates(Connection conn,\n        TriggerKey triggerKey, String newState, String oldState1,\n        String oldState2, String oldState3)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Update all triggers in the given group to the given new state, if they\n     * are in one of the given old states.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param matcher\n     *          the group matcher to evaluate against the known triggers\n     * @param newState\n     *          the new state for the trigger\n     * @param oldState1\n     *          one of the old state the trigger must be in\n     * @param oldState2\n     *          one of the old state the trigger must be in\n     * @param oldState3\n     *          one of the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    int updateTriggerGroupStateFromOtherStates(Connection conn,\n        GroupMatcher<TriggerKey> matcher, String newState, String oldState1,\n        String oldState2, String oldState3) throws SQLException;\n\n    /**\n     * <p>\n     * Update all of the triggers of the given group to the given new state, if\n     * they are in the given old state.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param matcher\n     *          the matcher to evaluate against the known triggers\n     * @param newState\n     *          the new state for the trigger group\n     * @param oldState\n     *          the old state the triggers must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    int updateTriggerGroupStateFromOtherState(Connection conn,\n        GroupMatcher<TriggerKey> matcher, String newState, String oldState)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Update the states of all triggers associated with the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @param state\n     *          the new state for the triggers\n     * @return the number of rows updated\n     */\n    int updateTriggerStatesForJob(Connection conn, JobKey jobKey,\n        String state) throws SQLException;\n\n    /**\n     * <p>\n     * Update the states of any triggers associated with the given job, that\n     * are the given current state.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @param state\n     *          the new state for the triggers\n     * @param oldState\n     *          the old state of the triggers\n     * @return the number of rows updated\n     */\n    int updateTriggerStatesForJobFromOtherState(Connection conn,\n        JobKey jobKey, String state, String oldState)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Delete the base trigger data for a trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the number of rows deleted\n     */\n    int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException;\n\n    /**\n     * <p>\n     * Select the number of triggers associated with a given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of triggers for the given job\n     */\n    int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException;\n\n    /**\n     * <p>\n     * Select the job to which the trigger is associated.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the <code>{@link org.quartz.JobDetail}</code> object\n     *         associated with the given trigger\n     */\n    JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper,\n        TriggerKey triggerKey) \n        throws ClassNotFoundException, SQLException, IOException;\n\n    /**\n     * <p>\n     * Select the job to which the trigger is associated. Allow option to load actual job class or not. When case of\n     * remove, we do not need to load the class, which in many cases, it's no longer exists.\n     * </p>\n     */\n    JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper,\n                                  TriggerKey triggerKey, boolean loadJobClass) throws ClassNotFoundException, SQLException, IOException;\n\n    /**\n     * <p>\n     * Select the triggers for a job\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return an array of <code>(@link org.quartz.Trigger)</code> objects\n     *         associated with a given job.\n     * @throws SQLException\n     * @throws JobPersistenceException \n     */\n    List<OperableTrigger> selectTriggersForJob(Connection conn, JobKey jobKey) throws SQLException, ClassNotFoundException,\n        IOException, JobPersistenceException;\n\n    /**\n     * <p>\n     * Select the triggers for a calendar\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calName\n     *          the name of the calendar\n     * @return an array of <code>(@link org.quartz.Trigger)</code> objects\n     *         associated with the given calendar.\n     * @throws SQLException\n     * @throws JobPersistenceException \n     */\n    List<OperableTrigger> selectTriggersForCalendar(Connection conn, String calName)\n        throws SQLException, ClassNotFoundException, IOException, JobPersistenceException;\n    /**\n     * <p>\n     * Select a trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the <code>{@link org.quartz.Trigger}</code> object\n     * @throws JobPersistenceException \n     */\n    OperableTrigger selectTrigger(Connection conn, TriggerKey triggerKey) throws SQLException, ClassNotFoundException,\n        IOException, JobPersistenceException;\n\n    /**\n     * Gets a list of trigger by job and trigger group matchers\n     * <br>\n     * Note: This requires the use of enhanced statements\n     * @param conn the connection\n     * @param jobMatcher Job Group Matcher\n     * @param triggerMatcher Trigger group matcher\n     * @return list of trigger, or empty list if no trigger found\n     * @throws SQLException\n     * @throws ClassNotFoundException\n     * @throws IOException\n     * @throws JobPersistenceException\n     */\n\n    List<OperableTrigger> getTriggersByJobAndTriggerGroup(Connection conn, GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws SQLException, ClassNotFoundException,\n        IOException, JobPersistenceException;\n\n    /**\n     * <p>\n     * Select a trigger's JobDataMap.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param triggerName\n     *          the name of the trigger\n     * @param groupName\n     *          the group containing the trigger\n     * @return the <code>{@link org.quartz.JobDataMap}</code> of the Trigger,\n     * never null, but possibly empty.\n     */\n    JobDataMap selectTriggerJobDataMap(Connection conn, String triggerName,\n        String groupName) throws SQLException, ClassNotFoundException,\n        IOException;\n\n    /**\n     * <p>\n     * Select a trigger' state value.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the <code>{@link org.quartz.Trigger}</code> object\n     */\n    String selectTriggerState(Connection conn, TriggerKey triggerKey) throws SQLException;\n\n    /**\n     * <p>\n     * Select a trigger' status (state and next fire time).\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return a <code>TriggerStatus</code> object, or null\n     */\n    TriggerStatus selectTriggerStatus(Connection conn,\n        TriggerKey triggerKey) throws SQLException;\n\n    /**\n     * <p>\n     * Select the total number of triggers stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of triggers stored\n     */\n    int selectNumTriggers(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the trigger group names that are stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> group names\n     */\n    List<String> selectTriggerGroups(Connection conn) throws SQLException;\n\n    List<String> selectTriggerGroups(Connection conn, GroupMatcher<TriggerKey> matcher) throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the triggers contained in a given group.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param matcher\n     *          to evaluate against known triggers\n     * @return a Set of <code>TriggerKey</code>s\n     */\n    Set<TriggerKey> selectTriggersInGroup(Connection conn, GroupMatcher<TriggerKey> matcher)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the triggers in a given state.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param state\n     *          the state the triggers must be in\n     * @return an array of trigger <code>Key</code> s\n     */\n    List<TriggerKey> selectTriggersInState(Connection conn, String state)\n        throws SQLException;\n\n    int insertPausedTriggerGroup(Connection conn, String groupName)\n        throws SQLException;\n\n    int deletePausedTriggerGroup(Connection conn, String groupName)\n        throws SQLException;\n\n    int deletePausedTriggerGroup(Connection conn, GroupMatcher<TriggerKey> matcher)\n        throws SQLException;\n\n    int deleteAllPausedTriggerGroups(Connection conn)\n        throws SQLException;\n\n    boolean isTriggerGroupPaused(Connection conn, String groupName)\n        throws SQLException;\n\n    Set<String> selectPausedTriggerGroups(Connection conn)\n        throws SQLException;\n    \n    boolean isExistingTriggerGroup(Connection conn, String groupName)\n        throws SQLException;\n\n    //---------------------------------------------------------------------------\n    // calendars\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert a new calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    int insertCalendar(Connection conn, String calendarName,\n        Calendar calendar) throws IOException, SQLException;\n\n    /**\n     * <p>\n     * Update a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    int updateCalendar(Connection conn, String calendarName,\n        Calendar calendar) throws IOException, SQLException;\n\n    /**\n     * <p>\n     * Check whether or not a calendar exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return true if the trigger exists, false otherwise\n     */\n    boolean calendarExists(Connection conn, String calendarName)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Select a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return the Calendar\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found be\n     *           found\n     * @throws IOException\n     *           if there were problems deserializing the calendar\n     */\n    Calendar selectCalendar(Connection conn, String calendarName)\n        throws ClassNotFoundException, IOException, SQLException;\n\n    /**\n     * <p>\n     * Check whether or not a calendar is referenced by any triggers.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return true if any triggers reference the calendar, false otherwise\n     */\n    boolean calendarIsReferenced(Connection conn, String calendarName)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Delete a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the trigger\n     * @return the number of rows deleted\n     */\n    int deleteCalendar(Connection conn, String calendarName)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Select the total number of calendars stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of calendars stored\n     */\n    int selectNumCalendars(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Select all of the stored calendars.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> calendar names\n     */\n    List<String> selectCalendars(Connection conn) throws SQLException;\n\n    //---------------------------------------------------------------------------\n    // trigger firing\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Select the next time that a trigger will be fired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the next fire time, or 0 if no trigger will be fired\n     * \n     * @deprecated Does not account for misfires.\n     */\n    @Deprecated\n    long selectNextFireTime(Connection conn) throws SQLException;\n\n    /**\n     * <p>\n     * Select the trigger that will be fired at the given fire time.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param fireTime\n     *          the time that the trigger will be fired\n     * @return a <code>{@link org.quartz.utils.Key}</code> representing the\n     *         trigger that will be fired at the given fire time, or null if no\n     *         trigger will be fired at that time\n     */\n    Key<?> selectTriggerForFireTime(Connection conn, long fireTime)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Select the next trigger which will fire to fire between the two given timestamps \n     * in ascending order of fire time, and then descending by priority.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param noLaterThan\n     *          highest value of <code>getNextFireTime()</code> of the triggers (exclusive)\n     * @param noEarlierThan \n     *          lowest value of <code>getNextFireTime()</code> of the triggers (inclusive)\n     *          \n     * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired.\n     * \n     * @deprecated - This remained for compatibility reason. Use {@link #selectTriggerToAcquire(Connection, long, long, int)} instead. \n     */\n    @Deprecated\n    List<TriggerKey> selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan)\n        throws SQLException;\n    \n    /**\n     * <p>\n     * Select the next trigger which will fire to fire between the two given timestamps \n     * in ascending order of fire time, and then descending by priority.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param noLaterThan\n     *          highest value of <code>getNextFireTime()</code> of the triggers (exclusive)\n     * @param noEarlierThan \n     *          highest value of <code>getNextFireTime()</code> of the triggers (inclusive)\n     * @param maxCount \n     *          maximum number of trigger keys allow to acquired in the returning list.\n     *          \n     * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired.\n     */\n    List<TriggerKey> selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan, int maxCount)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Insert a fired trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    int insertFiredTrigger(Connection conn, OperableTrigger trigger,\n        String state, JobDetail jobDetail) throws SQLException;\n\n    /**\n     * <p>\n     * Update a fired trigger record.  Will update the fields  \n     * \"firing instance\", \"fire time\", and \"state\".\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    int updateFiredTrigger(Connection conn, OperableTrigger trigger,\n        String state, JobDetail jobDetail) throws SQLException;\n\n    /**\n     * <p>\n     * Select the states of all fired-trigger records for a given trigger, or\n     * trigger group if trigger name is <code>null</code>.\n     * </p>\n     * \n     * @return a List of FiredTriggerRecord objects.\n     */\n    List<FiredTriggerRecord> selectFiredTriggerRecords(Connection conn, String triggerName, String groupName) throws SQLException;\n\n    /**\n     * <p>\n     * Select the states of all fired-trigger records for a given job, or job\n     * group if job name is <code>null</code>.\n     * </p>\n     * \n     * @return a List of FiredTriggerRecord objects.\n     */\n    List<FiredTriggerRecord> selectFiredTriggerRecordsByJob(Connection conn, String jobName, String groupName) throws SQLException;\n\n    /**\n     * <p>\n     * Select the states of all fired-trigger records for a given scheduler\n     * instance.\n     * </p>\n     * \n     * @return a List of FiredTriggerRecord objects.\n     */\n    List<FiredTriggerRecord> selectInstancesFiredTriggerRecords(Connection conn,\n        String instanceName) throws SQLException;\n\n    \n    /**\n     * <p>\n     * Select the distinct instance names of all fired-trigger records.\n     * </p>\n     * \n     * <p>\n     * This is useful when trying to identify orphaned fired triggers (a \n     * fired trigger without a scheduler state record.) \n     * </p>\n     * \n     * @return a Set of String objects.\n     */\n    Set<String> selectFiredTriggerInstanceNames(Connection conn) \n        throws SQLException;\n    \n    /**\n     * <p>\n     * Delete a fired trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param entryId\n     *          the fired trigger entry to delete\n     * @return the number of rows deleted\n     */\n    int deleteFiredTrigger(Connection conn, String entryId)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Get the number instances of the identified job currently executing.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * \n     * @return the number instances of the identified job currently executing.\n     */\n    int selectJobExecutionCount(Connection conn, JobKey jobKey) throws SQLException;\n\n    /**\n     * <p>\n     * Insert a scheduler-instance state record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of inserted rows.\n     */\n    int insertSchedulerState(Connection conn, String instanceId,\n        long checkInTime, long interval)\n        throws SQLException;\n\n    /**\n     * <p>\n     * Delete a scheduler-instance state record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of deleted rows.\n     */\n    int deleteSchedulerState(Connection conn, String instanceId)\n        throws SQLException;\n\n    \n    /**\n     * <p>\n     * Update a scheduler-instance state record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of updated rows.\n     */\n    int updateSchedulerState(Connection conn, String instanceId, long checkInTime)\n        throws SQLException;\n    \n    /**\n     * <p>\n     * A List of all current <code>SchedulerStateRecords</code>.\n     * </p>\n     * \n     * <p>\n     * If instanceId is not null, then only the record for the identified\n     * instance will be returned.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     */\n    List<SchedulerStateRecord> selectSchedulerStateRecords(Connection conn, String instanceId)\n        throws SQLException;\n\n    /**\n     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws SQLException\n     */\n    void clearData(Connection conn)\n        throws SQLException;\n\n\n    /**\n     * Returns true if enhanced statements for the database operations is enabled\n     * @return true if using enhanced statements\n     */\n    default boolean isUsingEnhancedStatements() {\n        return false;\n    }\n\n    /**\n     * Set to true to use enhanced statements for the database operations\n     * @param useEnhancedStatements true to use enhanced statements\n     */\n    default void setUseEnhancedStatements(boolean useEnhancedStatements) {\n        //no-op\n    }\n    \n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/FiredTriggerRecord.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.JobKey;\nimport org.quartz.TriggerKey;\n\n/**\n * <p>\n * Conveys the state of a fired-trigger record.\n * </p>\n * \n * @author James House\n */\npublic class FiredTriggerRecord implements java.io.Serializable {\n\n    private static final long serialVersionUID = -7183096398865657533L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private String fireInstanceId;\n\n    private long fireTimestamp;\n\n    private long scheduleTimestamp;\n    \n    private String schedulerInstanceId;\n\n    private TriggerKey triggerKey;\n\n    private String fireInstanceState;\n\n    private JobKey jobKey;\n\n    private boolean jobDisallowsConcurrentExecution;\n\n    private boolean jobRequestsRecovery;\n\n    private int priority;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public String getFireInstanceId() {\n        return fireInstanceId;\n    }\n\n    public long getFireTimestamp() {\n        return fireTimestamp;\n    }\n\n    public long getScheduleTimestamp() {\n        return scheduleTimestamp;\n    }\n\n    public boolean isJobDisallowsConcurrentExecution() {\n        return jobDisallowsConcurrentExecution;\n    }\n\n    public JobKey getJobKey() {\n        return jobKey;\n    }\n\n    public String getSchedulerInstanceId() {\n        return schedulerInstanceId;\n    }\n\n    public TriggerKey getTriggerKey() {\n        return triggerKey;\n    }\n\n    public String getFireInstanceState() {\n        return fireInstanceState;\n    }\n\n    public void setFireInstanceId(String string) {\n        fireInstanceId = string;\n    }\n\n    public void setFireTimestamp(long l) {\n        fireTimestamp = l;\n    }\n\n    public void setScheduleTimestamp(long l) {\n        scheduleTimestamp = l;\n    }\n\n    public void setJobDisallowsConcurrentExecution(boolean b) {\n        jobDisallowsConcurrentExecution = b;\n    }\n\n    public void setJobKey(JobKey key) {\n        jobKey = key;\n    }\n\n    public void setSchedulerInstanceId(String string) {\n        schedulerInstanceId = string;\n    }\n\n    public void setTriggerKey(TriggerKey key) {\n        triggerKey = key;\n    }\n\n    public void setFireInstanceState(String string) {\n        fireInstanceState = string;\n    }\n\n    public boolean isJobRequestsRecovery() {\n        return jobRequestsRecovery;\n    }\n\n    public void setJobRequestsRecovery(boolean b) {\n        jobRequestsRecovery = b;\n    }\n\n    public int getPriority() {\n        return priority;\n    }\n    \n\n    public void setPriority(int priority) {\n        this.priority = priority;\n    }\n    \n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/GaussDBDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for the GaussDB JDBC driver.\n * Notes: Original code of this file is based on PostgreSQLDelegate.\n *\n * </p>\n * \n * @author <a href=\"mailto:chenzhida@apache.org\">chen zhida</a>\n */\npublic class GaussDBDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        InputStream binaryInput;\n        byte[] bytes = rs.getBytes(colName);\n        \n        Object obj = null;\n        \n        if(bytes != null && bytes.length != 0) {\n            binaryInput = new ByteArrayInputStream(bytes);\n\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n\n        }\n        \n        return obj;\n    }\n\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            InputStream binaryInput;\n            byte[] bytes = rs.getBytes(colName);\n            if(bytes == null || bytes.length == 0) {\n                return null;\n            }\n            binaryInput = new ByteArrayInputStream(bytes);\n            return binaryInput;\n        }\n        return getObjectFromBlob(rs, colName);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/HSQLDBDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for the HSQLDB database.\n * </p>\n * \n * @author James House\n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class HSQLDBDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        InputStream binaryInput = rs.getBinaryStream(colName);\n\n        if(binaryInput == null || binaryInput.available() == 0) {\n            return null;\n        }\n        \n        Object obj;\n\n        try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n            obj = in.readObject();\n        }\n\n        return obj;\n    }\n\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            return rs.getBinaryStream(colName);\n        }\n        return getObjectFromBlob(rs, colName);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/InvalidConfigurationException.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\n/**\n * <p>\n * Exception class for when a driver delegate cannot be found for a given\n * configuration, or lack thereof.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class InvalidConfigurationException extends Exception {\n\n    private static final long serialVersionUID = 1836325935209404611L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public InvalidConfigurationException(String msg) {\n        super(msg);\n    }\n\n    public InvalidConfigurationException() {\n        super();\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/JTANonClusteredSemaphore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.util.HashSet;\n\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport jakarta.transaction.Synchronization;\nimport jakarta.transaction.SystemException;\nimport jakarta.transaction.Transaction;\nimport jakarta.transaction.TransactionManager;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Provides in memory thread/resource locking that is JTA \n * <code>{@link jakarta.transaction.Transaction}</code> aware.  \n * It is most appropriate for use when using \n * <code>{@link org.quartz.impl.jdbcjobstore.JobStoreCMT}</code> without clustering.\n * \n * <p>\n * This <code>Semaphore</code> implementation is <b>not</b> Quartz cluster safe.  \n * </p>\n *  \n * <p>\n * When a lock is obtained/released but there is no active JTA \n * <code>{@link jakarta.transaction.Transaction}</code>, then this <code>Semaphore</code> operates\n * just like <code>{@link org.quartz.impl.jdbcjobstore.SimpleSemaphore}</code>. \n * </p>\n * \n * <p>\n * By default, this class looks for the <code>{@link jakarta.transaction.TransactionManager}</code>\n * in JNDI under name \"java:TransactionManager\".  If this is not where your Application Server \n * registers it, you can modify the JNDI lookup location using the \n * \"transactionManagerJNDIName\" property.\n * </p>\n *\n * <p>\n * <b>IMPORTANT:</b>  This Semaphore implementation is currently experimental.  \n * It has been tested a limited amount on JBoss 4.0.3SP1.  If you do choose to \n * use it, any feedback would be most appreciated! \n * </p>\n * \n * @see org.quartz.impl.jdbcjobstore.SimpleSemaphore\n */\npublic class JTANonClusteredSemaphore implements Semaphore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String DEFAULT_TRANSACTION_MANAGER_LOCATION = \"java:TransactionManager\";\n\n    final ThreadLocal<HashSet<String>> lockOwners = new ThreadLocal<>();\n\n    final HashSet<String> locks = new HashSet<>();\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    private String transactionManagerJNDIName = DEFAULT_TRANSACTION_MANAGER_LOCATION;\n    \n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    public void setTransactionManagerJNDIName(String transactionManagerJNDIName) {\n        this.transactionManagerJNDIName = transactionManagerJNDIName;\n    }\n    \n    private HashSet<String> getThreadLocks() {\n        HashSet<String> threadLocks = lockOwners.get();\n        if (threadLocks == null) {\n            threadLocks = new HashSet<>();\n            lockOwners.set(threadLocks);\n        }\n        return threadLocks;\n    }\n\n    /**\n     * Grants a lock on the identified resource to the calling thread (blocking\n     * until it is available).\n     * \n     * @return true if the lock was obtained.\n     */\n    public synchronized boolean obtainLock(Connection conn, String lockName) throws LockException {\n\n        lockName = lockName.intern();\n\n        if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' is desired by: {}\", lockName, Thread.currentThread().getName());\n        }\n\n        if (!isLockOwner(conn, lockName)) {\n            if(log.isDebugEnabled()) {\n                log.debug(\"Lock '{}' is being obtained: {}\", lockName, Thread.currentThread().getName());\n            }\n            \n            while (locks.contains(lockName)) {\n                try {\n                    this.wait();\n                } catch (InterruptedException ie) {\n                    if(log.isDebugEnabled()) {\n                        log.debug(\"Lock '{}' was not obtained by: {}\", lockName, Thread.currentThread().getName());\n                    }\n                }\n            }\n\n            // If we are in a transaction, register a callback to actually release\n            // the lock when the transaction completes\n            Transaction t = getTransaction();\n            if (t != null) {\n                try {\n                    t.registerSynchronization(new SemaphoreSynchronization(lockName));\n                } catch (Exception e) {\n                    throw new LockException(\"Failed to register semaphore with Transaction.\", e);\n                }\n            }\n            \n            if(log.isDebugEnabled()) {\n                log.debug(\"Lock '{}' given to: {}\", lockName, Thread.currentThread().getName());\n            }\n            \n            \n            getThreadLocks().add(lockName);\n            locks.add(lockName);\n        } else if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' already owned by: {} -- but not owner!\", lockName, Thread.currentThread().getName(), new Exception(\"stack-trace of wrongful returner\"));\n        }\n\n        return true;\n    }\n\n    /**\n     * Helper method to get the current <code>{@link jakarta.transaction.Transaction}</code>\n     * from the <code>{@link jakarta.transaction.TransactionManager}</code> in JNDI.\n     * \n     * @return The current <code>{@link jakarta.transaction.Transaction}</code>, null if\n     * not currently in a transaction.\n     */\n    protected Transaction getTransaction() throws LockException{\n        InitialContext ic = null; \n        try {\n            ic = new InitialContext(); \n            TransactionManager tm = (TransactionManager)ic.lookup(transactionManagerJNDIName);\n            \n            return tm.getTransaction();\n        } catch (SystemException e) {\n            throw new LockException(\"Failed to get Transaction from TransactionManager\", e);\n        } catch (NamingException e) {\n            throw new LockException(\"Failed to find TransactionManager in JNDI under name: \" + transactionManagerJNDIName, e);\n        } finally {\n            if (ic != null) {\n                try {\n                    ic.close();\n                } catch (NamingException ignored) {\n                }\n            }\n        }\n    }\n    \n    /**\n     * Release the lock on the identified resource if it is held by the calling\n     * thread, unless currently in a JTA transaction.\n     */\n    public synchronized void releaseLock(String lockName) throws LockException {\n        releaseLock(lockName, false);\n    }\n    \n    /**\n     * Release the lock on the identified resource if it is held by the calling\n     * thread, unless currently in a JTA transaction.\n     * \n     * @param fromSynchronization True if this method is being invoked from\n     *      <code>{@link Synchronization}</code> notified of the enclosing \n     *      transaction having completed.\n     * \n     * @throws LockException Thrown if there was a problem accessing the JTA \n     *      <code>Transaction</code>.  Only relevant if <code>fromSynchronization</code>\n     *      is false.\n     */\n    protected synchronized void releaseLock(\n        String lockName, boolean fromSynchronization) throws LockException {\n        lockName = lockName.intern();\n\n        if (isLockOwner(null, lockName)) {\n            \n            if (!fromSynchronization) {\n                Transaction t = getTransaction();\n                if (t != null) {\n                    if(getLog().isDebugEnabled()) {\n                        getLog().debug(\"Lock '{}' is in a JTA transaction.  Return deferred by: {}\", lockName, Thread.currentThread().getName());\n                    }\n                    \n                    // If we are still in a transaction, then we don't want to \n                    // actually release the lock.\n                    return;\n                }\n            }\n            \n            if(getLog().isDebugEnabled()) {\n                getLog().debug(\"Lock '{}' returned by: {}\", lockName, Thread.currentThread().getName());\n            }\n            getThreadLocks().remove(lockName);\n            locks.remove(lockName);\n            this.notify();\n        } else if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Lock '{}' attempt to return by: {} -- but not owner!\", lockName, Thread.currentThread().getName(), new Exception(\"stack-trace of wrongful returner\"));\n        }\n    }\n\n    /**\n     * Determine whether the calling thread owns a lock on the identified\n     * resource.\n     */\n    public synchronized boolean isLockOwner(Connection conn, String lockName) {\n        lockName = lockName.intern();\n\n        return getThreadLocks().contains(lockName);\n    }\n\n    /**\n     * This Semaphore implementation does not use the database.\n     */\n    public boolean requiresConnection() {\n        return false;\n    }\n\n    /**\n     * Helper class that is registered with the active \n     * <code>{@link jakarta.transaction.Transaction}</code> so that the lock\n     * will be released when the transaction completes.\n     */\n    private class SemaphoreSynchronization implements Synchronization {\n        private final String lockName;\n        \n        public SemaphoreSynchronization(String lockName) {\n            this.lockName = lockName;\n        }\n        \n        public void beforeCompletion() {\n            // nothing to do...\n        }\n    \n        public void afterCompletion(int status) {\n            try {\n                releaseLock(lockName, true);\n            } catch (LockException e) {\n                // Ignore as can't be thrown with fromSynchronization set to true\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreCMT.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport org.quartz.JobPersistenceException;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.impl.jdbcjobstore.JobStoreSupport;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerSignaler;\nimport org.quartz.utils.DBConnectionManager;\n\n/**\n * <p>\n * <code>JobStoreCMT</code> is meant to be used in an application-server\n * environment that provides container-managed-transactions. No commit /\n * rollback will be handled by this class.\n * </p>\n * \n * <p>\n * If you need commit / rollback, use <code>{@link\n * org.quartz.impl.jdbcjobstore.JobStoreTX}</code>\n * instead.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n * @author Srinivas Venkatarangaiah\n *  \n */\npublic class JobStoreCMT extends JobStoreSupport {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected String nonManagedTxDsName;\n\n    // Great name huh?\n    protected boolean dontSetNonManagedTXConnectionAutoCommitFalse = false;\n\n    \n    protected boolean setTxIsolationLevelReadCommitted = false;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Set the name of the <code>DataSource</code> that should be used for\n     * performing database functions.\n     * </p>\n     */\n    public void setNonManagedTXDataSource(String nonManagedTxDsName) {\n        this.nonManagedTxDsName = nonManagedTxDsName;\n    }\n\n    /**\n     * <p>\n     * Get the name of the <code>DataSource</code> that should be used for\n     * performing database functions.\n     * </p>\n     */\n    public String getNonManagedTXDataSource() {\n        return nonManagedTxDsName;\n    }\n\n    public boolean isDontSetNonManagedTXConnectionAutoCommitFalse() {\n        return dontSetNonManagedTXConnectionAutoCommitFalse;\n    }\n\n    /**\n     * Don't call set autocommit(false) on connections obtained from the\n     * DataSource. This can be helpful in a few situations, such as if you\n     * have a driver that complains if it is called when it is already off.\n     * \n     * @param b\n     */\n    public void setDontSetNonManagedTXConnectionAutoCommitFalse(boolean b) {\n        dontSetNonManagedTXConnectionAutoCommitFalse = b;\n    }\n\n\n    public boolean isTxIsolationLevelReadCommitted() {\n        return setTxIsolationLevelReadCommitted;\n    }\n\n    /**\n     * Set the transaction isolation level of DB connections to sequential.\n     * \n     * @param b\n     */\n    public void setTxIsolationLevelReadCommitted(boolean b) {\n        setTxIsolationLevelReadCommitted = b;\n    }\n    \n\n    @Override\n    public void initialize(ClassLoadHelper loadHelper,\n            SchedulerSignaler signaler) throws SchedulerConfigException {\n\n        if (nonManagedTxDsName == null) {\n            throw new SchedulerConfigException(\n                \"Non-ManagedTX DataSource name not set!  \" +\n                \"If your 'org.quartz.jobStore.dataSource' is XA, then set \" + \n                \"'org.quartz.jobStore.nonManagedTXDataSource' to a non-XA \"+ \n                \"datasource (for the same DB).  \" + \n                \"Otherwise, you can set them to be the same.\");\n        }\n\n        if (getLockHandler() == null) {\n            // If the user hasn't specified an explicit lock handler, \n            // then we *must* use DB locks with CMT...\n            setUseDBLocks(true);\n        }\n\n        super.initialize(loadHelper, signaler);\n\n        getLog().info(\"JobStoreCMT initialized.\");\n    }\n    \n    @Override\n    public void shutdown() {\n\n        super.shutdown();\n        \n        try {\n            DBConnectionManager.getInstance().shutdown(getNonManagedTXDataSource());\n        } catch (SQLException sqle) {\n            getLog().warn(\"Database connection shutdown unsuccessful.\", sqle);\n        }\n    }\n\n    @Override\n    protected Connection getNonManagedTXConnection()\n        throws JobPersistenceException {\n        Connection conn;\n        try {\n            conn = DBConnectionManager.getInstance().getConnection(\n                    getNonManagedTXDataSource());\n        } catch (Throwable e) {\n            throw new JobPersistenceException(\n                \"Failed to obtain DB connection from data source '\"\n                        + getNonManagedTXDataSource() + \"': \"\n                        + e, e);\n        }\n\n        if (conn == null) { \n            throw new JobPersistenceException(\n                \"Could not get connection from DataSource '\"\n                        + getNonManagedTXDataSource() + \"'\"); \n        }\n\n        // Protect connection attributes we might change.\n        conn = getAttributeRestoringConnection(conn);\n        \n        // Set any connection attributes we are to override.\n        try {\n            if (!isDontSetNonManagedTXConnectionAutoCommitFalse()) {\n                conn.setAutoCommit(false);\n            }\n            \n            if (isTxIsolationLevelReadCommitted()) {\n                conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);\n            }\n        } catch (SQLException sqle) {\n            getLog().warn(\"Failed to override connection auto commit/transaction isolation.\", sqle);\n        } catch (Throwable e) {\n            try { conn.close(); } catch(Throwable tt) {}\n            \n            throw new JobPersistenceException(\n                \"Failure setting up connection.\", e);\n        }\n        \n        return conn;\n    }\n    \n    /**\n     * Execute the given callback having optionally acquired the given lock.  \n     * Because CMT assumes that the connection is already part of a managed\n     * transaction, it does not attempt to commit or rollback the \n     * enclosing transaction.\n     * \n     * @param lockName The name of the lock to acquire, for example \n     * \"TRIGGER_ACCESS\".  If null, then no lock is acquired, but the\n     * txCallback is still executed in a transaction.\n     * \n     * @see JobStoreSupport#executeInNonManagedTXLock(java.lang.String, org.quartz.impl.jdbcjobstore.JobStoreSupport.TransactionCallback, org.quartz.impl.jdbcjobstore.JobStoreSupport.TransactionValidator) \n     * @see JobStoreTX#executeInLock(java.lang.String, org.quartz.impl.jdbcjobstore.JobStoreSupport.TransactionCallback) \n     * @see JobStoreSupport#getNonManagedTXConnection()\n     * @see JobStoreSupport#getConnection()\n     */\n    @Override\n    protected Object executeInLock(\n            String lockName, \n            TransactionCallback txCallback) throws JobPersistenceException {\n        boolean transOwner = false;\n        Connection conn = null;\n        try {\n            if (lockName != null) {\n                // If we aren't using db locks, then delay getting DB connection \n                // until after acquiring the lock since it isn't needed.\n                if (getLockHandler().requiresConnection()) {\n                    conn = getConnection();\n                }\n                \n                transOwner = getLockHandler().obtainLock(conn, lockName);\n            }\n\n            if (conn == null) {\n                conn = getConnection();\n            }\n\n            return txCallback.execute(conn);\n        } finally {\n            try {\n                releaseLock(lockName, transOwner);\n            } finally {\n                cleanupConnection(conn);\n            }\n        }\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Proxy;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.ObjectAlreadyExistsException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.DefaultThreadExecutor;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.matchers.StringMatcher;\nimport org.quartz.impl.matchers.StringMatcher.StringOperatorName;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.SchedulerSignaler;\nimport org.quartz.spi.ThreadExecutor;\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.quartz.spi.TriggerFiredResult;\nimport org.quartz.utils.DBConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * <p>\n * Contains base functionality for JDBC-based JobStore implementations.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n */\npublic abstract class JobStoreSupport implements JobStore, Constants {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected static final String LOCK_TRIGGER_ACCESS = \"TRIGGER_ACCESS\";\n\n    protected static final String LOCK_STATE_ACCESS = \"STATE_ACCESS\";\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected String dsName;\n\n    protected String tablePrefix = DEFAULT_TABLE_PREFIX;\n\n    protected boolean useProperties = false;\n\n    protected String instanceId;\n\n    protected String instanceName;\n    \n    protected String delegateClassName;\n\n    protected String delegateInitString;\n    \n    protected Class<? extends DriverDelegate> delegateClass = StdJDBCDelegate.class;\n\n    protected final HashMap<String, Calendar> calendarCache = new HashMap<>();\n\n    private DriverDelegate delegate;\n\n    private long misfireThreshold = 60000L; // one minute\n\n    private boolean dontSetAutoCommitFalse = false;\n\n    private boolean isClustered = false;\n\n    private boolean useDBLocks = false;\n    \n    private boolean lockOnInsert = true;\n\n    private Semaphore lockHandler = null; // set in initialize() method...\n\n    private String selectWithLockSQL = null;\n\n    private long clusterCheckinInterval = 7500L;\n\n    private ClusterManager clusterManagementThread = null;\n\n    private MisfireHandler misfireHandler = null;\n\n    private ClassLoadHelper classLoadHelper;\n\n    private SchedulerSignaler schedSignaler;\n\n    protected int maxToRecoverAtATime = 20;\n\n    private boolean useEnhancedStatements = false;\n    \n    private boolean setTxIsolationLevelSequential = false;\n    \n    private boolean acquireTriggersWithinLock = false;\n    \n    private long dbRetryInterval = 15000L; // 15 secs\n    \n    private boolean makeThreadsDaemons = false;\n\n    private boolean threadsInheritInitializersClassLoadContext = false;\n    private ClassLoader initializersLoader = null;\n    \n    private boolean doubleCheckLockMisfireHandler = true;\n    \n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    private ThreadExecutor threadExecutor = new DefaultThreadExecutor();\n    \n    private volatile boolean schedulerRunning = false;\n    private volatile boolean shutdown = false;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Set the name of the <code>DataSource</code> that should be used for\n     * performing database functions.\n     * </p>\n     */\n    public void setDataSource(String dsName) {\n        this.dsName = dsName;\n    }\n\n    /**\n     * <p>\n     * Get the name of the <code>DataSource</code> that should be used for\n     * performing database functions.\n     * </p>\n     */\n    public String getDataSource() {\n        return dsName;\n    }\n\n    /**\n     * <p>\n     * Set the prefix that should be pre-pended to all table names.\n     * </p>\n     */\n    public void setTablePrefix(String prefix) {\n        if (prefix == null) {\n            prefix = \"\";\n        }\n\n        this.tablePrefix = prefix;\n    }\n\n    /**\n     * <p>\n     * Get the prefix that should be pre-pended to all table names.\n     * </p>\n     */\n    public String getTablePrefix() {\n        return tablePrefix;\n    }\n\n    /**\n     * <p>\n     * Set whether String-only properties will be handled in JobDataMaps.\n     * </p>\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setUseProperties(String useProp) {\n        if (useProp == null) {\n            useProp = \"false\";\n        }\n\n        this.useProperties = Boolean.parseBoolean(useProp);\n    }\n\n    /**\n     * <p>\n     * Get whether String-only properties will be handled in JobDataMaps.\n     * </p>\n     */\n    public boolean canUseProperties() {\n        return useProperties;\n    }\n\n    /**\n     * <p>\n     * Set the instance Id of the Scheduler (must be unique within a cluster).\n     * </p>\n     */\n    public void setInstanceId(String instanceId) {\n        this.instanceId = instanceId;\n    }\n\n    /**\n     * <p>\n     * Get the instance Id of the Scheduler (must be unique within a cluster).\n     * </p>\n     */\n    public String getInstanceId() {\n\n        return instanceId;\n    }\n\n    /**\n     * Set the instance name of the Scheduler (must be unique within this server instance).\n     */\n    public void setInstanceName(String instanceName) {\n        this.instanceName = instanceName;\n    }\n\n    public void setThreadPoolSize(final int poolSize) {\n        //\n    }\n    \n    public void setThreadExecutor(ThreadExecutor threadExecutor) {\n        this.threadExecutor = threadExecutor;\n    }\n    \n    public ThreadExecutor getThreadExecutor() {\n        return threadExecutor;\n    }\n    \n\n    /**\n     * Get the instance name of the Scheduler (must be unique within this server instance).\n     */\n    public String getInstanceName() {\n\n        return instanceName;\n    }\n\n    public long getEstimatedTimeToReleaseAndAcquireTrigger() {\n        return 70;\n    }\n\n    /**\n     * <p>\n     * Set whether this instance is part of a cluster.\n     * </p>\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setIsClustered(boolean isClustered) {\n        this.isClustered = isClustered;\n    }\n\n    /**\n     * <p>\n     * Get whether this instance is part of a cluster.\n     * </p>\n     */\n    public boolean isClustered() {\n        return isClustered;\n    }\n\n    /**\n     * <p>\n     * Get the frequency (in milliseconds) at which this instance \"checks-in\"\n     * with the other instances of the cluster. -- Affects the rate of\n     * detecting failed instances.\n     * </p>\n     */\n    public long getClusterCheckinInterval() {\n        return clusterCheckinInterval;\n    }\n\n    /**\n     * <p>\n     * Set the frequency (in milliseconds) at which this instance \"checks-in\"\n     * with the other instances of the cluster. -- Affects the rate of\n     * detecting failed instances.\n     * </p>\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setClusterCheckinInterval(long l) {\n        clusterCheckinInterval = l;\n    }\n\n    /**\n     * <p>\n     * Get the maximum number of misfired triggers that the misfire handling\n     * thread will try to recover at one time (within one transaction).  The\n     * default is 20.\n     * </p>\n     */\n    public int getMaxMisfiresToHandleAtATime() {\n        return maxToRecoverAtATime;\n    }\n\n    /**\n     * <p>\n     * Set the maximum number of misfired triggers that the misfire handling\n     * thread will try to recover at one time (within one transaction).  The\n     * default is 20.\n     * </p>\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setMaxMisfiresToHandleAtATime(int maxToRecoverAtATime) {\n        this.maxToRecoverAtATime = maxToRecoverAtATime;\n    }\n\n    /**\n     * @return Returns the dbRetryInterval.\n     */\n    public long getDbRetryInterval() {\n        return dbRetryInterval;\n    }\n    /**\n     * @param dbRetryInterval The dbRetryInterval to set.\n     */\n    public void setDbRetryInterval(long dbRetryInterval) {\n        this.dbRetryInterval = dbRetryInterval;\n    }\n    \n    /**\n     * <p>\n     * Set whether this instance should use database-based thread\n     * synchronization.\n     * </p>\n     */\n    public void setUseDBLocks(boolean useDBLocks) {\n        this.useDBLocks = useDBLocks;\n    }\n\n    /**\n     * <p>\n     * Get whether this instance should use database-based thread\n     * synchronization.\n     * </p>\n     */\n    public boolean getUseDBLocks() {\n        return useDBLocks;\n    }\n\n    public boolean isLockOnInsert() {\n        return lockOnInsert;\n    }\n    \n    /**\n     * Whether or not to obtain locks when inserting new jobs/triggers.  \n     * <p>\n     * Defaults to <code>true</code>, which is safest. Some databases (such as \n     * MS SQLServer) seem to require this to avoid deadlocks under high load,\n     * while others seem to do fine without.  Settings this to false means\n     * isolation guarantees between job scheduling and trigger acquisition are\n     * entirely enforced by the database.  Depending on the database and it's\n     * configuration this may cause unusual scheduling behaviors.\n     * \n     * <p>Setting this property to <code>false</code> will provide a \n     * significant performance increase during the addition of new jobs \n     * and triggers.</p>\n     * \n     * @param lockOnInsert whether locking should be used when inserting new jobs/triggers\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setLockOnInsert(boolean lockOnInsert) {\n        this.lockOnInsert = lockOnInsert;\n    }\n    \n    public long getMisfireThreshold() {\n        return misfireThreshold;\n    }\n\n    /**\n     * The the number of milliseconds by which a trigger must have missed its\n     * next-fire-time, in order for it to be considered \"misfired\" and thus\n     * have its misfire instruction applied.\n     * \n     * @param misfireThreshold the misfire threshold to use, in millis\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setMisfireThreshold(long misfireThreshold) {\n        if (misfireThreshold < 1) {\n            throw new IllegalArgumentException(\n                    \"Misfire threshold must be larger than 0\");\n        }\n        this.misfireThreshold = misfireThreshold;\n    }\n\n    public boolean isDontSetAutoCommitFalse() {\n        return dontSetAutoCommitFalse;\n    }\n\n    /**\n     * Don't call set autocommit(false) on connections obtained from the\n     * DataSource. This can be helpful in a few situations, such as if you\n     * have a driver that complains if it is called when it is already off.\n     * \n     * @param b whether or not autocommit should be set to false on db connections\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setDontSetAutoCommitFalse(boolean b) {\n        dontSetAutoCommitFalse = b;\n    }\n\n    public boolean isTxIsolationLevelSerializable() {\n        return setTxIsolationLevelSequential;\n    }\n\n    /**\n     * Set the transaction isolation level of DB connections to sequential.\n     * \n     * @param b whether isolation level should be set to sequential.\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setTxIsolationLevelSerializable(boolean b) {\n        setTxIsolationLevelSequential = b;\n    }\n\n    /**\n     * Whether or not the query and update to acquire a Trigger for firing\n     * should be performed after obtaining an explicit DB lock (to avoid \n     * possible race conditions on the trigger's db row).  This is the\n     * behavior prior to Quartz 1.6.3, but is considered unnecessary for most\n     * databases (due to the nature of the SQL update that is performed), \n     * and therefore a superfluous performance hit.     \n     */\n    public boolean isAcquireTriggersWithinLock() {\n        return acquireTriggersWithinLock;\n    }\n\n    /**\n     * Whether or not the query and update to acquire a Trigger for firing\n     * should be performed after obtaining an explicit DB lock.  This is the\n     * behavior prior to Quartz 1.6.3, but is considered unnecessary for most\n     * databases, and therefore a superfluous performance hit.     \n     * \n     * However, if batch acquisition is used, it is important for this behavior\n     * to be used for all dbs.\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setAcquireTriggersWithinLock(boolean acquireTriggersWithinLock) {\n        this.acquireTriggersWithinLock = acquireTriggersWithinLock;\n    }\n\n    \n    /**\n     * <p>\n     * Set the JDBC driver delegate class.\n     * </p>\n     * \n     * @param delegateClassName\n     *          the delegate class name\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setDriverDelegateClass(String delegateClassName)\n        throws InvalidConfigurationException {\n        synchronized(this) {\n            this.delegateClassName = delegateClassName;\n        }\n    }\n\n    /**\n     * <p>\n     * Get the JDBC driver delegate class name.\n     * </p>\n     * \n     * @return the delegate class name\n     */\n    public String getDriverDelegateClass() {\n        return delegateClassName;\n    }\n\n    /**\n     * <p>\n     * Set the JDBC driver delegate's initialization string.\n     * </p>\n     * \n     * @param delegateInitString\n     *          the delegate init string\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setDriverDelegateInitString(String delegateInitString)\n        throws InvalidConfigurationException {\n        this.delegateInitString = delegateInitString;\n    }\n\n    /**\n     * <p>\n     * Get the JDBC driver delegate's initialization string.\n     * </p>\n     * \n     * @return the delegate init string\n     */\n    public String getDriverDelegateInitString() {\n        return delegateInitString;\n    }\n\n    public String getSelectWithLockSQL() {\n        return selectWithLockSQL;\n    }\n\n    /**\n     * <p>\n     * set the SQL statement to use to select and lock a row in the \"locks\"\n     * table.\n     * </p>\n     * \n     * @see StdRowLockSemaphore\n     */\n    public void setSelectWithLockSQL(String string) {\n        selectWithLockSQL = string;\n    }\n\n    protected ClassLoadHelper getClassLoadHelper() {\n        return classLoadHelper;\n    }\n\n    /**\n     * Get whether the threads spawned by this JobStore should be\n     * marked as daemon.  Possible threads include the <code>MisfireHandler</code> \n     * and the <code>ClusterManager</code>.\n     * \n     * @see Thread#setDaemon(boolean)\n     */\n    public boolean getMakeThreadsDaemons() {\n        return makeThreadsDaemons;\n    }\n\n    /**\n     * Set whether the threads spawned by this JobStore should be\n     * marked as daemon.  Possible threads include the <code>MisfireHandler</code> \n     * and the <code>ClusterManager</code>.\n     *\n     * @see Thread#setDaemon(boolean)\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setMakeThreadsDaemons(boolean makeThreadsDaemons) {\n        this.makeThreadsDaemons = makeThreadsDaemons;\n    }\n    \n    /**\n     * Get whether to set the class load context of spawned threads to that\n     * of the initializing thread.\n     */\n    public boolean isThreadsInheritInitializersClassLoadContext() {\n        return threadsInheritInitializersClassLoadContext;\n    }\n\n    /**\n     * Set whether to set the class load context of spawned threads to that\n     * of the initializing thread.\n     */\n    public void setThreadsInheritInitializersClassLoadContext(\n            boolean threadsInheritInitializersClassLoadContext) {\n        this.threadsInheritInitializersClassLoadContext = threadsInheritInitializersClassLoadContext;\n    }\n\n    /**\n     * Get whether to check to see if there are Triggers that have misfired\n     * before actually acquiring the lock to recover them.  This should be \n     * set to false if the majority of the time, there are misfired\n     * Triggers.\n     */\n    public boolean getDoubleCheckLockMisfireHandler() {\n        return doubleCheckLockMisfireHandler;\n    }\n\n    /**\n     * Set whether to check to see if there are Triggers that have misfired\n     * before actually acquiring the lock to recover them.  This should be \n     * set to false if the majority of the time, there are misfired\n     * Triggers.\n     */\n    @SuppressWarnings(\"UnusedDeclaration\") /* called reflectively */\n    public void setDoubleCheckLockMisfireHandler(\n            boolean doubleCheckLockMisfireHandler) {\n        this.doubleCheckLockMisfireHandler = doubleCheckLockMisfireHandler;\n    }\n\n    @Override\n    public long getAcquireRetryDelay(int failureCount) {\n        return dbRetryInterval;\n    }\n\n    //---------------------------------------------------------------------------\n    // interface methods\n    //---------------------------------------------------------------------------\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler before the <code>JobStore</code> is\n     * used, in order to give it a chance to initialize.\n     * </p>\n     */\n    public void initialize(ClassLoadHelper loadHelper,\n            SchedulerSignaler signaler) throws SchedulerConfigException {\n\n        if (dsName == null) { \n            throw new SchedulerConfigException(\"DataSource name not set.\"); \n        }\n\n        classLoadHelper = loadHelper;\n        if(isThreadsInheritInitializersClassLoadContext()) {\n            log.info(\"JDBCJobStore threads will inherit ContextClassLoader of thread: {}\", Thread.currentThread().getName());\n            initializersLoader = Thread.currentThread().getContextClassLoader();\n        }\n        \n        this.schedSignaler = signaler;\n\n        // If the user hasn't specified an explicit lock handler, then \n        // choose one based on CMT/Clustered/UseDBLocks.\n        if (getLockHandler() == null) {\n            \n            // If the user hasn't specified an explicit lock handler, \n            // then we *must* use DB locks with clustering\n            if (isClustered()) {\n                setUseDBLocks(true);\n            }\n            \n            if (getUseDBLocks()) {\n                if(getDriverDelegateClass() != null && getDriverDelegateClass().contains(MSSQLDelegate.class.getSimpleName())) {\n                    if(getSelectWithLockSQL() == null) {\n                        String msSqlDflt = \"SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE \" + COL_SCHEDULER_NAME + \" = {1} AND LOCK_NAME = ?\";\n                        getLog().info(\"Detected usage of MSSQLDelegate class - defaulting 'selectWithLockSQL' to '{}'.\", msSqlDflt);\n                        setSelectWithLockSQL(msSqlDflt);\n                    }\n                }\n                getLog().info(\"Using db table-based data access locking (synchronization).\");\n                setLockHandler(new StdRowLockSemaphore(getTablePrefix(), getInstanceName(), getSelectWithLockSQL()));\n            } else {\n                getLog().info(\n                    \"Using thread monitor-based data access locking (synchronization).\");\n                setLockHandler(new SimpleSemaphore());\n            }\n        }\n\n    }\n   \n    /**\n     * @see org.quartz.spi.JobStore#schedulerStarted()\n     */\n    public void schedulerStarted() throws SchedulerException {\n\n        if (isClustered()) {\n            clusterManagementThread = new ClusterManager();\n            if(initializersLoader != null)\n                clusterManagementThread.setContextClassLoader(initializersLoader);\n            clusterManagementThread.initialize();\n        } else {\n            try {\n                recoverJobs();\n            } catch (SchedulerException se) {\n                throw new SchedulerConfigException(\n                        \"Failure occurred during job recovery.\", se);\n            }\n        }\n\n        misfireHandler = new MisfireHandler();\n        if(initializersLoader != null)\n            misfireHandler.setContextClassLoader(initializersLoader);\n        misfireHandler.initialize();\n        schedulerRunning = true;\n        \n        getLog().debug(\"JobStore background threads started (as scheduler was started).\");\n    }\n    \n    public void schedulerPaused() {\n        schedulerRunning = false;\n    }\n    \n    public void schedulerResumed() {\n        schedulerRunning = true;\n    }\n    \n    /**\n     * <p>\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * it should free up all of it's resources because the scheduler is\n     * shutting down.\n     * </p>\n     */\n    public void shutdown() {\n        shutdown = true;\n        \n        if (misfireHandler != null) {\n            misfireHandler.shutdown();\n            try {\n                misfireHandler.join();\n            } catch (InterruptedException ignore) {\n            }\n        }\n\n        if (clusterManagementThread != null) {\n            clusterManagementThread.shutdown();\n            try {\n                clusterManagementThread.join();\n            } catch (InterruptedException ignore) {\n            }\n        }\n\n        try {\n            DBConnectionManager.getInstance().shutdown(getDataSource());\n        } catch (SQLException sqle) {\n            getLog().warn(\"Database connection shutdown unsuccessful.\", sqle);\n        }        \n        \n        getLog().debug(\"JobStore background threads shutdown.\");\n    }\n\n    public boolean supportsPersistence() {\n        return true;\n    }\n\n    //---------------------------------------------------------------------------\n    // helper methods for subclasses\n    //---------------------------------------------------------------------------\n\n    protected abstract Connection getNonManagedTXConnection()\n        throws JobPersistenceException;\n\n    /**\n     * Wrap the given <code>Connection</code> in a Proxy such that attributes \n     * that might be set will be restored before the connection is closed \n     * (and potentially restored to a pool).\n     */\n    protected Connection getAttributeRestoringConnection(Connection conn) {\n        return (Connection) Proxy.newProxyInstance(\n                Thread.currentThread().getContextClassLoader(),\n                new Class[] { Connection.class },\n                new AttributeRestoringConnectionInvocationHandler(conn));\n    }\n    \n    protected Connection getConnection() throws JobPersistenceException {\n        Connection conn;\n        try {\n            conn = DBConnectionManager.getInstance().getConnection(\n                    getDataSource());\n        } catch (Throwable e) {\n            throw new JobPersistenceException(\n                    \"Failed to obtain DB connection from data source '\"\n                    + getDataSource() + \"': \" + e, e);\n        }\n\n        if (conn == null) { \n            throw new JobPersistenceException(\n                \"Could not get connection from DataSource '\"\n                + getDataSource() + \"'\"); \n        }\n\n        // Protect connection attributes we might change.\n        conn = getAttributeRestoringConnection(conn);\n\n        // Set any connection attributes we are to override.\n        try {\n            if (!isDontSetAutoCommitFalse()) {\n                conn.setAutoCommit(false);\n            }\n\n            if(isTxIsolationLevelSerializable()) {\n                conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);\n            }\n        } catch (SQLException sqle) {\n            getLog().warn(\"Failed to override connection auto commit/transaction isolation.\", sqle);\n        } catch (Throwable e) {\n            try { conn.close(); } catch(Throwable ignored) {}\n            \n            throw new JobPersistenceException(\n                \"Failure setting up connection.\", e);\n        }\n    \n        return conn;\n    }\n\n    protected void releaseLock(String lockName, boolean doIt) {\n        if (doIt) {\n            try {\n                getLockHandler().releaseLock(lockName);\n            } catch (LockException le) {\n                getLog().error(\"Error returning lock: {}\", le.getMessage(), le);\n            }\n        }\n    }\n\n    /**\n     * Recover any failed or misfired jobs and clean up the data store as\n     * appropriate.\n     * \n     * @throws JobPersistenceException if jobs could not be recovered\n     */\n    protected void recoverJobs() throws JobPersistenceException {\n        executeInNonManagedTXLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    recoverJobs(conn);\n                }\n            }, null);\n    }\n    \n    /**\n     * <p>\n     * Will recover any failed or misfired jobs and clean up the data store as\n     * appropriate.\n     * </p>\n     * \n     * @throws JobPersistenceException\n     *           if jobs could not be recovered\n     */\n    protected void recoverJobs(Connection conn) throws JobPersistenceException {\n        try {\n            // update inconsistent job states\n            int rows = getDelegate().updateTriggerStatesFromOtherStates(conn,\n                    STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED);\n\n            rows += getDelegate().updateTriggerStatesFromOtherStates(conn,\n                        STATE_PAUSED, STATE_PAUSED_BLOCKED, STATE_PAUSED_BLOCKED);\n\n            getLog().info(\"Freed {} triggers from 'acquired' / 'blocked' state.\", rows);\n\n            // clean up misfired jobs\n            recoverMisfiredJobs(conn, true);\n            \n            // recover jobs marked for recovery that were not fully executed\n            List<OperableTrigger> recoveringJobTriggers = getDelegate()\n                    .selectTriggersForRecoveringJobs(conn);\n            getLog()\n                    .info(\"Recovering {} jobs that were in-progress at the time of the last shut-down.\", recoveringJobTriggers.size());\n\n            for (OperableTrigger recoveringJobTrigger: recoveringJobTriggers) {\n                if (jobExists(conn, recoveringJobTrigger.getJobKey())) {\n                    recoveringJobTrigger.computeFirstFireTime(null);\n                    storeTrigger(conn, recoveringJobTrigger, null, false,\n                            STATE_WAITING, false, true);\n                }\n            }\n            getLog().info(\"Recovery complete.\");\n\n            // remove lingering 'complete' triggers...\n            List<TriggerKey> cts = getDelegate().selectTriggersInState(conn, STATE_COMPLETE);\n            for(TriggerKey ct: cts) {\n                removeTrigger(conn, ct);\n            }\n            getLog().info(\"Removed {} 'complete' triggers.\", cts.size());\n            \n            // clean up any fired trigger entries\n            int n = getDelegate().deleteFiredTriggers(conn);\n            getLog().info(\"Removed {} stale fired job entries.\", n);\n        } catch (JobPersistenceException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new JobPersistenceException(\"Couldn't recover jobs: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    protected long getMisfireTime() {\n        long misfireTime = System.currentTimeMillis();\n        if (getMisfireThreshold() > 0) {\n            misfireTime -= getMisfireThreshold();\n        }\n\n        return (misfireTime > 0) ? misfireTime : 0;\n    }\n\n    /**\n     * Helper class for returning the composite result of trying\n     * to recover misfired jobs.\n     */\n    protected static class RecoverMisfiredJobsResult {\n        public static final RecoverMisfiredJobsResult NO_OP =\n            new RecoverMisfiredJobsResult(false, 0, Long.MAX_VALUE);\n        \n        private final boolean _hasMoreMisfiredTriggers;\n        private final int _processedMisfiredTriggerCount;\n        private final long _earliestNewTime;\n        \n        public RecoverMisfiredJobsResult(\n            boolean hasMoreMisfiredTriggers, int processedMisfiredTriggerCount, long earliestNewTime) {\n            _hasMoreMisfiredTriggers = hasMoreMisfiredTriggers;\n            _processedMisfiredTriggerCount = processedMisfiredTriggerCount;\n            _earliestNewTime = earliestNewTime;\n        }\n        \n        public boolean hasMoreMisfiredTriggers() {\n            return _hasMoreMisfiredTriggers;\n        }\n        public int getProcessedMisfiredTriggerCount() {\n            return _processedMisfiredTriggerCount;\n        } \n        public long getEarliestNewTime() {\n            return _earliestNewTime;\n        } \n    }\n    \n    protected RecoverMisfiredJobsResult recoverMisfiredJobs(\n        Connection conn, boolean recovering)\n        throws JobPersistenceException, SQLException {\n\n        // If recovering, we want to handle all of the misfired\n        // triggers right away.\n        int maxMisfiresToHandleAtATime = \n            (recovering) ? -1 : getMaxMisfiresToHandleAtATime();\n        \n        List<TriggerKey> misfiredTriggers = new LinkedList<>();\n        long earliestNewTime = Long.MAX_VALUE;\n        // We must still look for the MISFIRED state in case triggers were left \n        // in this state when upgrading to this version that does not support it. \n        boolean hasMoreMisfiredTriggers =\n            getDelegate().hasMisfiredTriggersInState(\n                conn, STATE_WAITING, getMisfireTime(), \n                maxMisfiresToHandleAtATime, misfiredTriggers);\n\n        if (hasMoreMisfiredTriggers) {\n            getLog().info(\"Handling the first {} triggers that missed their scheduled fire-time.  More misfired triggers remain to be processed.\", misfiredTriggers.size());\n        } else if (!misfiredTriggers.isEmpty()) {\n            getLog().info(\"Handling {} trigger(s) that missed their scheduled fire-time.\", misfiredTriggers.size());\n        } else {\n            getLog().debug(\n                \"Found 0 triggers that missed their scheduled fire-time.\");\n            return RecoverMisfiredJobsResult.NO_OP; \n        }\n\n        for (TriggerKey triggerKey: misfiredTriggers) {\n            OperableTrigger trig;\n\n            try {\n                trig = retrieveTrigger(conn, triggerKey);\n            } catch (Exception e) {\n                getLog().error(\"Error retrieving the misfired trigger: {}\", triggerKey, e);\n                continue;\n            }\n\n            if (trig == null) {\n                continue;\n            }\n\n            try {\n                doUpdateOfMisfiredTrigger(conn, trig, false, STATE_WAITING, recovering);\n            } catch (Exception e) {\n                getLog().error(\"Error updating misfired trigger: {}\", trig.getKey(), e);\n                continue;\n            }\n            if(trig.getNextFireTime() != null && trig.getNextFireTime().getTime() < earliestNewTime)\n                earliestNewTime = trig.getNextFireTime().getTime();\n        }\n\n        return new RecoverMisfiredJobsResult(\n                hasMoreMisfiredTriggers, misfiredTriggers.size(), earliestNewTime);\n    }\n\n    protected boolean updateMisfiredTrigger(Connection conn,\n            TriggerKey triggerKey, String newStateIfNotComplete, boolean forceState)\n        throws JobPersistenceException {\n        try {\n\n            OperableTrigger trig = retrieveTrigger(conn, triggerKey);\n\n            long misfireTime = System.currentTimeMillis();\n            if (getMisfireThreshold() > 0) {\n                misfireTime -= getMisfireThreshold();\n            }\n\n            if (trig.getNextFireTime().getTime() > misfireTime) {\n                return false;\n            }\n\n            doUpdateOfMisfiredTrigger(conn, trig, forceState, newStateIfNotComplete, false);\n\n            return true;\n\n        } catch (Exception e) {\n            throw new JobPersistenceException(\n                    \"Couldn't update misfired trigger '\" + triggerKey + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    private void doUpdateOfMisfiredTrigger(Connection conn, OperableTrigger trig, boolean forceState, String newStateIfNotComplete, boolean recovering) throws JobPersistenceException {\n        Calendar cal = null;\n        if (trig.getCalendarName() != null) {\n            cal = retrieveCalendar(conn, trig.getCalendarName());\n        }\n\n        schedSignaler.notifyTriggerListenersMisfired(trig);\n\n        trig.updateAfterMisfire(cal);\n\n        if (trig.getNextFireTime() == null) {\n            storeTrigger(conn, trig,\n                null, true, STATE_COMPLETE, forceState, recovering);\n            schedSignaler.notifySchedulerListenersFinalized(trig);\n        } else {\n            storeTrigger(conn, trig, null, true, newStateIfNotComplete,\n                    forceState, recovering);\n        }\n    }\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     * \n     * @param newJob\n     *          The <code>JobDetail</code> to be stored.\n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists.\n     */\n    public void storeJobAndTrigger(final JobDetail newJob,\n            final OperableTrigger newTrigger) \n        throws JobPersistenceException {\n        executeInLock(\n            (isLockOnInsert()) ? LOCK_TRIGGER_ACCESS : null,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    storeJob(conn, newJob, false);\n                    storeTrigger(conn, newTrigger, newJob, false,\n                            Constants.STATE_WAITING, false, false);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.JobDetail}</code>.\n     * </p>\n     * \n     * @param newJob\n     *          The <code>JobDetail</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Job</code> existing in the\n     *          <code>JobStore</code> with the same name and group should be\n     *          over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     */\n    public void storeJob(final JobDetail newJob,\n        final boolean replaceExisting) throws JobPersistenceException {\n        executeInLock(\n            (isLockOnInsert() || replaceExisting) ? LOCK_TRIGGER_ACCESS : null,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    storeJob(conn, newJob, replaceExisting);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Insert or update a job.\n     * </p>\n     */\n    protected void storeJob(Connection conn, \n            JobDetail newJob, boolean replaceExisting)\n        throws JobPersistenceException {\n\n        boolean existingJob = jobExists(conn, newJob.getKey());\n        try {\n            if (existingJob) {\n                if (!replaceExisting) { \n                    throw new ObjectAlreadyExistsException(newJob); \n                }\n                getDelegate().updateJobDetail(conn, newJob);\n            }\n            else if (getDelegate().insertJobDetail(conn, newJob) < 1) {\n                throw new JobPersistenceException(\"Couldn't store job. Insert failed.\");\n            }\n        } catch (IOException | SQLException e) {\n            throw new JobPersistenceException(\"Couldn't store job: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Check existence of a given job.\n     * </p>\n     */\n    protected boolean jobExists(Connection conn, JobKey jobKey) throws JobPersistenceException {\n        try {\n            return getDelegate().jobExists(conn, jobKey);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't determine job existence (\" + jobKey + \"): \" + e.getMessage(), e);\n        }\n    }\n\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     * \n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Trigger</code> existing in\n     *          the <code>JobStore</code> with the same name and group should\n     *          be over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Trigger</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     */\n    public void storeTrigger(final OperableTrigger newTrigger,\n        final boolean replaceExisting) throws JobPersistenceException {\n        executeInLock(\n            (isLockOnInsert() || replaceExisting) ? LOCK_TRIGGER_ACCESS : null,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    storeTrigger(conn, newTrigger, null, replaceExisting,\n                        STATE_WAITING, false, false);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Insert or update a trigger.\n     * </p>\n     */\n    @SuppressWarnings(\"ConstantConditions\")\n    protected void storeTrigger(Connection conn,\n            OperableTrigger newTrigger, JobDetail job, boolean replaceExisting, String state,\n            boolean forceState, boolean recovering)\n        throws JobPersistenceException {\n\n        boolean existingTrigger = triggerExists(conn, newTrigger.getKey());\n\n        if ((existingTrigger) && (!replaceExisting)) { \n            throw new ObjectAlreadyExistsException(newTrigger); \n        }\n        \n        try {\n\n            boolean shouldBePaused;\n\n            if (!forceState) {\n                shouldBePaused = getDelegate().isTriggerGroupPaused(\n                        conn, newTrigger.getKey().getGroup());\n\n                if(!shouldBePaused) {\n                    shouldBePaused = getDelegate().isTriggerGroupPaused(conn,\n                            ALL_GROUPS_PAUSED);\n\n                    if (shouldBePaused) {\n                        getDelegate().insertPausedTriggerGroup(conn, newTrigger.getKey().getGroup());\n                    }\n                }\n\n                if (shouldBePaused && (state.equals(STATE_WAITING) || state.equals(STATE_ACQUIRED))) {\n                    state = STATE_PAUSED;\n                }\n            }\n\n            if(job == null) {\n                job = retrieveJob(conn, newTrigger.getJobKey());\n            }\n            if (job == null) {\n                throw new JobPersistenceException(\"The job (\"\n                        + newTrigger.getJobKey()\n                        + \") referenced by the trigger does not exist.\");\n            }\n\n            if (job.isConcurrentExecutionDisallowed() && !recovering) { \n                state = checkBlockedState(conn, job.getKey(), state);\n            }\n            \n            if (existingTrigger) {\n                getDelegate().updateTrigger(conn, newTrigger, state, job);\n            } else {\n                getDelegate().insertTrigger(conn, newTrigger, state, job);\n            }\n        } catch (Exception e) {\n            throw new JobPersistenceException(\"Couldn't store trigger '\" + newTrigger.getKey() + \"' for '\" \n                    + newTrigger.getJobKey() + \"' job:\" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Check existence of a given trigger.\n     * </p>\n     */\n    protected boolean triggerExists(Connection conn, TriggerKey key) throws JobPersistenceException {\n        try {\n            return getDelegate().triggerExists(conn, key);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't determine trigger existence (\" + key + \"): \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Job}</code> with the given\n     * name, and any <code>{@link org.quartz.Trigger}</code> s that reference\n     * it.\n     * </p>\n     * \n     * <p>\n     * If removal of the <code>Job</code> results in an empty group, the\n     * group should be removed from the <code>JobStore</code>'s list of\n     * known group names.\n     * </p>\n     * \n     * @return <code>true</code> if a <code>Job</code> with the given name and\n     *         group was found and removed from the store.\n     */\n    public boolean removeJob(final JobKey jobKey) throws JobPersistenceException {\n        return (Boolean) executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new TransactionCallback() {\n                    public Object execute(Connection conn) throws JobPersistenceException {\n                        return removeJob(conn, jobKey) ?\n                                Boolean.TRUE : Boolean.FALSE;\n                    }\n                });\n    }\n    \n    protected boolean removeJob(Connection conn, final JobKey jobKey)\n        throws JobPersistenceException {\n\n        try {\n            List<TriggerKey> jobTriggers = getDelegate().selectTriggerKeysForJob(conn, jobKey);\n            for (TriggerKey jobTrigger: jobTriggers) {\n                deleteTriggerAndChildren(conn, jobTrigger);\n            }\n\n            return deleteJobAndChildren(conn, jobKey);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't remove job: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    public boolean removeJobs(final List<JobKey> jobKeys) throws JobPersistenceException {\n\n        return (Boolean) executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new TransactionCallback() {\n                    public Object execute(Connection conn) throws JobPersistenceException {\n                        boolean allFound = true;\n\n                        // FUTURE_TODO: make this more efficient with a true bulk operation...\n                        for (JobKey jobKey : jobKeys)\n                            allFound = removeJob(conn, jobKey) && allFound;\n\n                        return allFound ? Boolean.TRUE : Boolean.FALSE;\n                    }\n                });\n    }\n\n    public boolean removeTriggers(final List<TriggerKey> triggerKeys)\n            throws JobPersistenceException {\n        return executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                conn -> {\n                    boolean allFound = true;\n\n                    // FUTURE_TODO: make this more efficient with a true bulk operation...\n                    for (TriggerKey triggerKey : triggerKeys)\n                        allFound &= removeTrigger(conn, triggerKey);\n\n                    return allFound;\n                });\n    }\n        \n    public void storeJobsAndTriggers(\n            final Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, final boolean replace)\n            throws JobPersistenceException {\n\n        executeInLock(\n                (isLockOnInsert() || replace) ? LOCK_TRIGGER_ACCESS : null,\n                new VoidTransactionCallback() {\n                    public void executeVoid(Connection conn) throws JobPersistenceException {\n                        \n                        // FUTURE_TODO: make this more efficient with a true bulk operation...\n                        for(JobDetail job: triggersAndJobs.keySet()) {\n                            storeJob(conn, job, replace);\n                            for(Trigger trigger: triggersAndJobs.get(job)) {\n                                storeTrigger(conn, (OperableTrigger) trigger, job, replace,\n                                        Constants.STATE_WAITING, false, false);\n                            }\n                        }\n                    }\n                });\n    }    \n    \n    /**\n     * Delete a job and its listeners.\n     * \n     * @see #removeJob(java.sql.Connection, org.quartz.JobKey)\n     * @see #removeTrigger(Connection, TriggerKey)\n     */\n    private boolean deleteJobAndChildren(Connection conn, JobKey key)\n        throws NoSuchDelegateException, SQLException {\n\n        return (getDelegate().deleteJobDetail(conn, key) > 0);\n    }\n    \n    /**\n     * Delete a trigger, its listeners, and its Simple/Cron/BLOB sub-table entry.\n     * \n     * @see #removeJob(java.sql.Connection, org.quartz.JobKey)\n     * @see #removeTrigger(Connection, TriggerKey)\n     * @see #replaceTrigger(Connection, TriggerKey, OperableTrigger)\n     */\n    private boolean deleteTriggerAndChildren(Connection conn, TriggerKey key)\n        throws SQLException, NoSuchDelegateException {\n\n        return (getDelegate().deleteTrigger(conn, key) > 0);\n    }\n    \n    /**\n     * <p>\n     * Retrieve the <code>{@link org.quartz.JobDetail}</code> for the given\n     * <code>{@link org.quartz.Job}</code>.\n     * </p>\n     * \n     * @return The desired <code>Job</code>, or null if there is no match.\n     */\n    public JobDetail retrieveJob(final JobKey jobKey) throws JobPersistenceException {\n        return (JobDetail)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> retrieveJob(conn, jobKey));\n    }\n\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException {\n        return (List<JobDetail>) executeWithoutLock(\n                (TransactionCallback) conn -> retrieveJobs(conn, matcher));\n    }\n\n    protected List<JobDetail> retrieveJobs(Connection conn, GroupMatcher<JobKey> matcher) throws JobPersistenceException {\n        try {\n            return getDelegate().selectJobDetails(conn, matcher,\n                getClassLoadHelper());\n        } catch (ClassNotFoundException e) {\n            throw new JobPersistenceException(\n                \"Couldn't retrieve job because a required class was not found: \"\n                    + e.getMessage(), e);\n        } catch (IOException e) {\n            throw new JobPersistenceException(\n                \"Couldn't retrieve job because the BLOB couldn't be deserialized: \"\n                    + e.getMessage(), e);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't retrieve job: \"\n                + e.getMessage(), e);\n        }\n    }\n    \n    protected JobDetail retrieveJob(Connection conn, JobKey key) throws JobPersistenceException {\n        try {\n            return getDelegate().selectJobDetail(conn, key,\n                    getClassLoadHelper());\n        } catch (ClassNotFoundException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't retrieve job because a required class was not found: \"\n                            + e.getMessage(), e);\n        } catch (IOException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't retrieve job because the BLOB couldn't be deserialized: \"\n                            + e.getMessage(), e);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't retrieve job: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given name.\n     * </p>\n     * \n     * <p>\n     * If removal of the <code>Trigger</code> results in an empty group, the\n     * group should be removed from the <code>JobStore</code>'s list of\n     * known group names.\n     * </p>\n     * \n     * <p>\n     * If removal of the <code>Trigger</code> results in an 'orphaned' <code>Job</code>\n     * that is not 'durable', then the <code>Job</code> should be deleted\n     * also.\n     * </p>\n     * \n     * @return <code>true</code> if a <code>Trigger</code> with the given\n     *         name and group was found and removed from the store.\n     */\n    public boolean removeTrigger(final TriggerKey triggerKey) throws JobPersistenceException {\n        return (Boolean) executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new TransactionCallback() {\n                    public Object execute(Connection conn) throws JobPersistenceException {\n                        return removeTrigger(conn, triggerKey) ?\n                                Boolean.TRUE : Boolean.FALSE;\n                    }\n                });\n    }\n    \n    protected boolean removeTrigger(Connection conn, TriggerKey key)\n        throws JobPersistenceException {\n        boolean removedTrigger;\n        try {\n            // this must be called before we delete the trigger, obviously\n            JobDetail job = getDelegate().selectJobForTrigger(conn,\n                    getClassLoadHelper(), key, false);\n\n            removedTrigger = \n                deleteTriggerAndChildren(conn, key);\n\n            if (null != job && !job.isDurable()) {\n                int numTriggers = getDelegate().selectNumTriggersForJob(conn,\n                        job.getKey());\n                if (numTriggers == 0) {\n                    // Don't call removeJob() because we don't want to check for\n                    // triggers again.\n                    deleteJobAndChildren(conn, job.getKey());\n                }\n            }\n        } catch (ClassNotFoundException | SQLException | IOException e) {\n            throw new JobPersistenceException(\"Couldn't remove trigger: \"\n                    + e.getMessage(), e);\n        }\n\n        return removedTrigger;\n    }\n\n    /** \n     * @see org.quartz.spi.JobStore#replaceTrigger(TriggerKey, OperableTrigger)\n     */\n    public boolean replaceTrigger(final TriggerKey triggerKey, \n            final OperableTrigger newTrigger) throws JobPersistenceException {\n        return (Boolean) executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new TransactionCallback() {\n                    public Object execute(Connection conn) throws JobPersistenceException {\n                        return replaceTrigger(conn, triggerKey, newTrigger) ?\n                                Boolean.TRUE : Boolean.FALSE;\n                    }\n                });\n    }\n    \n    protected boolean replaceTrigger(Connection conn, \n            TriggerKey key, OperableTrigger newTrigger)\n        throws JobPersistenceException {\n        try {\n            // this must be called before we delete the trigger, obviously\n            JobDetail job = getDelegate().selectJobForTrigger(conn,\n                    getClassLoadHelper(), key);\n\n            if (job == null) {\n                return false;\n            }\n            \n            if (!newTrigger.getJobKey().equals(job.getKey())) {\n                throw new JobPersistenceException(\"New trigger is not related to the same job as the old trigger.\");\n            }\n            \n            boolean removedTrigger = \n                deleteTriggerAndChildren(conn, key);\n            \n            storeTrigger(conn, newTrigger, job, false, STATE_WAITING, false, false);\n\n            return removedTrigger;\n        } catch (ClassNotFoundException | SQLException | IOException e) {\n            throw new JobPersistenceException(\"Couldn't remove trigger: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     * \n     * @return The desired <code>Trigger</code>, or null if there is no\n     *         match.\n     */\n    public OperableTrigger retrieveTrigger(final TriggerKey triggerKey) throws JobPersistenceException {\n        return (OperableTrigger)executeWithoutLock( // no locks necessary for read...\n            new TransactionCallback() {\n                public Object execute(Connection conn) throws JobPersistenceException {\n                    return retrieveTrigger(conn, triggerKey);\n                }\n            });\n    }\n    \n    protected OperableTrigger retrieveTrigger(Connection conn, TriggerKey key)\n        throws JobPersistenceException {\n        try {\n\n            return getDelegate().selectTrigger(conn, key);\n        } catch (Exception e) {\n            throw new JobPersistenceException(\"Couldn't retrieve trigger: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the current state of the identified <code>{@link Trigger}</code>.\n     * </p>\n     * \n     * @see TriggerState#NORMAL\n     * @see TriggerState#PAUSED\n     * @see TriggerState#COMPLETE\n     * @see TriggerState#ERROR\n     * @see TriggerState#NONE\n     */\n    public TriggerState getTriggerState(final TriggerKey triggerKey) throws JobPersistenceException {\n        return (TriggerState)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> getTriggerState(conn, triggerKey));\n    }\n    \n    public TriggerState getTriggerState(Connection conn, TriggerKey key)\n        throws JobPersistenceException {\n        try {\n            String ts = getDelegate().selectTriggerState(conn, key);\n\n            if (ts == null) {\n                return TriggerState.NONE;\n            }\n\n            switch (ts) {\n                case STATE_DELETED:\n                    return TriggerState.NONE;\n                case STATE_COMPLETE:\n                    return TriggerState.COMPLETE;\n                case STATE_PAUSED:\n                    return TriggerState.PAUSED;\n                case STATE_PAUSED_BLOCKED:\n                    return TriggerState.PAUSED;\n                case STATE_ERROR:\n                    return TriggerState.ERROR;\n                case STATE_BLOCKED:\n                    return TriggerState.BLOCKED;\n            }\n\n            return TriggerState.NORMAL;\n\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't determine state of trigger (\" + key + \"): \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Reset the current state of the identified <code>{@link Trigger}</code>\n     * from {@link TriggerState#ERROR} to {@link TriggerState#NORMAL} or\n     * {@link TriggerState#PAUSED} as appropriate.\n     *\n     * <p>Only affects triggers that are in ERROR state - if identified trigger is not\n     * in that state then the result is a no-op.</p>\n     *\n     * <p>The result will be the trigger returning to the normal, waiting to\n     * be fired state, unless the trigger's group has been paused, in which\n     * case it will go into the PAUSED state.</p>\n     */\n    public void resetTriggerFromErrorState(final TriggerKey triggerKey) throws JobPersistenceException {\n        executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new VoidTransactionCallback() {\n                    public void executeVoid(Connection conn) throws JobPersistenceException {\n                        resetTriggerFromErrorState(conn, triggerKey);\n                    }\n                });\n    }\n\n    void resetTriggerFromErrorState(Connection conn, final TriggerKey triggerKey)\n        throws JobPersistenceException {\n\n        try {\n            String newState = STATE_WAITING;\n\n            if(getDelegate().isTriggerGroupPaused(conn, triggerKey.getGroup())) {\n                newState = STATE_PAUSED;\n            }\n\n            getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, newState, STATE_ERROR);\n\n            getLog().info(\"Trigger {} reset from ERROR state to: {}\", triggerKey, newState);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't reset from error state of trigger (\" + triggerKey + \"): \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.Calendar}</code>.\n     * </p>\n     * \n     * @param calName\n     *          The name of the calendar.\n     * @param calendar\n     *          The <code>Calendar</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Calendar</code> existing\n     *          in the <code>JobStore</code> with the same name and group\n     *          should be over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Calendar</code> with the same name already\n     *           exists, and replaceExisting is set to false.\n     */\n    public void storeCalendar(final String calName,\n        final Calendar calendar, final boolean replaceExisting, final boolean updateTriggers)\n        throws JobPersistenceException {\n        executeInLock(\n            (isLockOnInsert() || updateTriggers) ? LOCK_TRIGGER_ACCESS : null,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    storeCalendar(conn, calName, calendar, replaceExisting, updateTriggers);\n                }\n            });\n    }\n    \n    protected void storeCalendar(Connection conn, \n            String calName, Calendar calendar, boolean replaceExisting, boolean updateTriggers)\n        throws JobPersistenceException {\n        try {\n            boolean existingCal = calendarExists(conn, calName);\n            if (existingCal && !replaceExisting) { \n                throw new ObjectAlreadyExistsException(\n                    \"Calendar with name '\" + calName + \"' already exists.\"); \n            }\n\n            if (existingCal) {\n                if (getDelegate().updateCalendar(conn, calName, calendar) < 1) { \n                    throw new JobPersistenceException(\n                        \"Couldn't store calendar.  Update failed.\"); \n                }\n                \n                if(updateTriggers) {\n                    // FUTURE_TODO: make this more efficient with a true bulk operation...\n                    List<OperableTrigger> trigs;\n                    trigs = getDelegate().selectTriggersForCalendar(conn, calName);\n\n                    for(OperableTrigger trigger: trigs) {\n                        trigger.updateWithNewCalendar(calendar, getMisfireThreshold());\n                        storeTrigger(conn, trigger, null, true, STATE_WAITING, false, false);\n                    }\n                }\n            } else {\n                if (getDelegate().insertCalendar(conn, calName, calendar) < 1) { \n                    throw new JobPersistenceException(\n                        \"Couldn't store calendar.  Insert failed.\"); \n                }\n            }\n\n            if (!isClustered) {\n                calendarCache.put(calName, calendar); // lazy-cache\n            }\n\n        } catch (IOException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't store calendar because the BLOB couldn't be serialized: \"\n                            + e.getMessage(), e);\n        } catch (ClassNotFoundException | SQLException e) {\n            throw new JobPersistenceException(\"Couldn't store calendar: \"\n                    + e.getMessage(), e);\n        }\n    }\n    \n    protected boolean calendarExists(Connection conn, String calName)\n        throws JobPersistenceException {\n        try {\n            return getDelegate().calendarExists(conn, calName);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't determine calendar existence (\" + calName + \"): \"\n                            + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Calendar}</code> with the\n     * given name.\n     * </p>\n     * \n     * <p>\n     * If removal of the <code>Calendar</code> would result in\n     * <code>Trigger</code>s pointing to nonexistent calendars, then a\n     * <code>JobPersistenceException</code> will be thrown.</p>\n     *       *\n     * @param calName The name of the <code>Calendar</code> to be removed.\n     * @return <code>true</code> if a <code>Calendar</code> with the given name\n     * was found and removed from the store.\n     */\n    public boolean removeCalendar(final String calName)\n        throws JobPersistenceException {\n        return (Boolean) executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new TransactionCallback() {\n                    public Object execute(Connection conn) throws JobPersistenceException {\n                        return removeCalendar(conn, calName) ?\n                                Boolean.TRUE : Boolean.FALSE;\n                    }\n                });\n    }\n    \n    protected boolean removeCalendar(Connection conn, \n            String calName) throws JobPersistenceException {\n        try {\n            if (getDelegate().calendarIsReferenced(conn, calName)) { \n                throw new JobPersistenceException(\n                    \"Calender cannot be removed if it referenced by a trigger!\"); \n            }\n\n            if (!isClustered) {\n                calendarCache.remove(calName);\n            }\n\n            return (getDelegate().deleteCalendar(conn, calName) > 0);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't remove calendar: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     * \n     * @param calName\n     *          The name of the <code>Calendar</code> to be retrieved.\n     * @return The desired <code>Calendar</code>, or null if there is no\n     *         match.\n     */\n    public Calendar retrieveCalendar(final String calName)\n        throws JobPersistenceException {\n        return (Calendar)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> retrieveCalendar(conn, calName));\n    }\n    \n    protected Calendar retrieveCalendar(Connection conn,\n            String calName)\n        throws JobPersistenceException {\n        // all calendars are persistent, but we can lazy-cache them during run\n        // time as long as we aren't running clustered.\n        Calendar cal = (isClustered) ? null : calendarCache.get(calName);\n        if (cal != null) {\n            return cal;\n        }\n\n        try {\n            cal = getDelegate().selectCalendar(conn, calName);\n            if (!isClustered) {\n                calendarCache.put(calName, cal); // lazy-cache...\n            }\n            return cal;\n        } catch (ClassNotFoundException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't retrieve calendar because a required class was not found: \"\n                            + e.getMessage(), e);\n        } catch (IOException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't retrieve calendar because the BLOB couldn't be deserialized: \"\n                            + e.getMessage(), e);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't retrieve calendar: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.Job}</code> s that are\n     * stored in the <code>JobStore</code>.\n     * </p>\n     */\n    public int getNumberOfJobs()\n        throws JobPersistenceException {\n        return (Integer) executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getNumberOfJobs);\n    }\n    \n    protected int getNumberOfJobs(Connection conn)\n        throws JobPersistenceException {\n        try {\n            return getDelegate().selectNumJobs(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain number of jobs: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.Trigger}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     * </p>\n     */\n    public int getNumberOfTriggers()\n        throws JobPersistenceException {\n        return (Integer) executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getNumberOfTriggers);\n    }\n    \n    protected int getNumberOfTriggers(Connection conn)\n        throws JobPersistenceException {\n        try {\n            return getDelegate().selectNumTriggers(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain number of triggers: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.Calendar}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     * </p>\n     */\n    public int getNumberOfCalendars()\n        throws JobPersistenceException {\n        return (Integer) executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getNumberOfCalendars);\n    }\n    \n    protected int getNumberOfCalendars(Connection conn)\n        throws JobPersistenceException {\n        try {\n            return getDelegate().selectNumCalendars(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain number of calendars: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Job}</code> s that\n     * matcher the given groupMatcher.\n     * </p>\n     * \n     * <p>\n     * If there are no jobs in the given group name, the result should be an empty Set\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<JobKey> getJobKeys(final GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException {\n        return (Set<JobKey>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> getJobNames(conn, matcher));\n    }\n    \n    protected Set<JobKey> getJobNames(Connection conn,\n            GroupMatcher<JobKey> matcher) throws JobPersistenceException {\n        Set<JobKey> jobNames;\n\n        try {\n            jobNames = getDelegate().selectJobsInGroup(conn, matcher);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't obtain job names: \"\n                    + e.getMessage(), e);\n        }\n\n        return jobNames;\n    }\n    \n    \n    /**\n     * Determine whether a {@link Job} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param jobKey the identifier to check for\n     * @return true if a Job exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    public boolean checkExists(final JobKey jobKey) throws JobPersistenceException {\n        return (Boolean)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> checkExists(conn, jobKey));\n    }\n   \n    protected boolean checkExists(Connection conn, JobKey jobKey) throws JobPersistenceException {\n        try {\n            return getDelegate().jobExists(conn, jobKey);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't check for existence of job: \"\n                    + e.getMessage(), e);\n        }\n    }\n    \n    /**\n     * Determine whether a {@link Trigger} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param triggerKey the identifier to check for\n     * @return true if a Trigger exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    public boolean checkExists(final TriggerKey triggerKey) throws JobPersistenceException {\n        return (Boolean)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> checkExists(conn, triggerKey));\n    }\n    \n    protected boolean checkExists(Connection conn, TriggerKey triggerKey) throws JobPersistenceException {\n        try {\n            return getDelegate().triggerExists(conn, triggerKey);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't check for existence of job: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws JobPersistenceException\n     */\n    public void clearAllSchedulingData() throws JobPersistenceException {\n        executeInLock(\n                LOCK_TRIGGER_ACCESS,\n                new VoidTransactionCallback() {\n                    public void executeVoid(Connection conn) throws JobPersistenceException {\n                        clearAllSchedulingData(conn);\n                    }\n                });\n    }\n    \n    protected void clearAllSchedulingData(Connection conn) throws JobPersistenceException {\n        try {\n            getDelegate().clearData(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Error clearing scheduling data: \" + e.getMessage(), e);\n        }\n    }\n    \n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code> s\n     * that match the given group Matcher.\n     * </p>\n     * \n     * <p>\n     * If there are no triggers in the given group name, the result should be a\n     * an empty Set (not <code>null</code>).\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<TriggerKey> getTriggerKeys(final GroupMatcher<TriggerKey> matcher)\n        throws JobPersistenceException {\n        return (Set<TriggerKey>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> getTriggerNames(conn, matcher));\n    }\n    \n    protected Set<TriggerKey> getTriggerNames(Connection conn,\n            GroupMatcher<TriggerKey> matcher) throws JobPersistenceException {\n\n        Set<TriggerKey> trigNames;\n\n        try {\n            trigNames = getDelegate().selectTriggersInGroup(conn, matcher);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't obtain trigger names: \"\n                    + e.getMessage(), e);\n        }\n\n        return trigNames;\n    }\n\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Job}</code>\n     * groups.\n     * </p>\n     * \n     * <p>\n     * If there are no known group names, the result should be a zero-length\n     * array (not <code>null</code>).\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getJobGroupNames()\n        throws JobPersistenceException {\n        return (List<String>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getJobGroupNames);\n    }\n    \n    protected List<String> getJobGroupNames(Connection conn)\n        throws JobPersistenceException {\n\n        List<String> groupNames;\n\n        try {\n            groupNames = getDelegate().selectJobGroups(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't obtain job groups: \"\n                    + e.getMessage(), e);\n        }\n\n        return groupNames;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code>\n     * groups.\n     * </p>\n     * \n     * <p>\n     * If there are no known group names, the result should be a zero-length\n     * array (not <code>null</code>).\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getTriggerGroupNames()\n        throws JobPersistenceException {\n        return (List<String>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getTriggerGroupNames);\n    }\n    \n    protected List<String> getTriggerGroupNames(Connection conn) throws JobPersistenceException {\n\n        List<String> groupNames;\n\n        try {\n            groupNames = getDelegate().selectTriggerGroups(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain trigger groups: \" + e.getMessage(), e);\n        }\n\n        return groupNames;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Calendar}</code> s\n     * in the <code>JobStore</code>.\n     * </p>\n     * \n     * <p>\n     * If there are no Calendars in the given group name, the result should be\n     * a zero-length array (not <code>null</code>).\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<String> getCalendarNames()\n        throws JobPersistenceException {\n        return (List<String>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getCalendarNames);\n    }\n    \n    protected List<String> getCalendarNames(Connection conn)\n        throws JobPersistenceException {\n        try {\n            return getDelegate().selectCalendars(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain trigger groups: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Get all of the Triggers that are associated to the given Job.\n     * </p>\n     * \n     * <p>\n     * If there are no matches, a zero-length array should be returned.\n     * </p>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<OperableTrigger> getTriggersForJob(final JobKey jobKey) throws JobPersistenceException {\n        return (List<OperableTrigger>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) conn -> getTriggersForJob(conn, jobKey));\n    }\n    \n    protected List<OperableTrigger> getTriggersForJob(Connection conn,\n            JobKey key)\n        throws JobPersistenceException {\n        List<OperableTrigger> list;\n\n        try {\n            list = getDelegate()\n                    .selectTriggersForJob(conn, key);\n        } catch (Exception e) {\n            throw new JobPersistenceException(\n                    \"Couldn't obtain triggers for job: \" + e.getMessage(), e);\n        }\n\n        return list;\n    }\n\n    public List<OperableTrigger> getTriggersByJobAndTriggerGroup(GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws JobPersistenceException {\n        return (List<OperableTrigger>)executeWithoutLock( // no locks necessary for read...\n            (TransactionCallback) conn -> getTriggersByJobAndTriggerGroup(conn, jobMatcher, triggerMatcher));\n    }\n\n    protected List<OperableTrigger> getTriggersByJobAndTriggerGroup(Connection conn, GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws JobPersistenceException {\n        GroupMatcher<JobKey> jMatcher = jobMatcher == null ? GroupMatcher.anyGroup() : jobMatcher;\n        GroupMatcher<TriggerKey> tMatcher = triggerMatcher == null ? GroupMatcher.anyGroup() : triggerMatcher;\n        try {\n            return getDelegate().getTriggersByJobAndTriggerGroup(conn, jMatcher, tMatcher);\n        } catch (JobPersistenceException jpe) {\n            throw jpe;\n        } catch (Exception e) {\n            throw new JobPersistenceException(\"Couldn't obtain triggers for job: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause the <code>{@link org.quartz.Trigger}</code> with the given name.\n     * </p>\n     * \n     * @see #resumeTrigger(TriggerKey)\n     */\n    public void pauseTrigger(final TriggerKey triggerKey) throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    pauseTrigger(conn, triggerKey);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Pause the <code>{@link org.quartz.Trigger}</code> with the given name.\n     * </p>\n     * \n     * @see #resumeTrigger(Connection, TriggerKey)\n     */\n    public void pauseTrigger(Connection conn, \n            TriggerKey triggerKey)\n        throws JobPersistenceException {\n\n        try {\n            String oldState = getDelegate().selectTriggerState(conn,\n                    triggerKey);\n\n            if (oldState.equals(STATE_WAITING)\n                    || oldState.equals(STATE_ACQUIRED)) {\n\n                getDelegate().updateTriggerState(conn, triggerKey,\n                        STATE_PAUSED);\n            } else if (oldState.equals(STATE_BLOCKED)) {\n                getDelegate().updateTriggerState(conn, triggerKey,\n                        STATE_PAUSED_BLOCKED);\n            }\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't pause trigger '\"\n                    + triggerKey + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause the <code>{@link org.quartz.Job}</code> with the given name - by\n     * pausing all of its current <code>Trigger</code>s.\n     * </p>\n     * \n     * @see #resumeJob(JobKey)\n     */\n    public void pauseJob(final JobKey jobKey) throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    List<OperableTrigger> triggers = getTriggersForJob(conn, jobKey);\n                    for (OperableTrigger trigger: triggers) {\n                        pauseTrigger(conn, trigger.getKey());\n                    }\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.Job}s</code> matching the given\n     * groupMatcher - by pausing all of their <code>Trigger</code>s.\n     * </p>\n     * \n     * @see #resumeJobs(org.quartz.impl.matchers.GroupMatcher)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> pauseJobs(final GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException {\n        return (Set<String>) executeInLock(\n            LOCK_TRIGGER_ACCESS,\n                (TransactionCallback) conn -> {\n                    Set<String> groupNames = new HashSet<>();\n                    Set<JobKey> jobNames = getJobNames(conn, matcher);\n\n                    for (JobKey jobKey : jobNames) {\n                        List<OperableTrigger> triggers = getTriggersForJob(conn, jobKey);\n                        for (OperableTrigger trigger : triggers) {\n                            pauseTrigger(conn, trigger.getKey());\n                        }\n                        groupNames.add(jobKey.getGroup());\n                    }\n\n                    return groupNames;\n                }\n        );\n    }\n    \n    /**\n     * Determines if a Trigger for the given job should be blocked.  \n     * State can only transition to STATE_PAUSED_BLOCKED/BLOCKED from \n     * PAUSED/STATE_WAITING respectively.\n     * \n     * @return STATE_PAUSED_BLOCKED, BLOCKED, or the currentState. \n     */\n    protected String checkBlockedState(\n            Connection conn, JobKey jobKey, String currentState)\n        throws JobPersistenceException {\n\n        // State can only transition to BLOCKED from PAUSED or WAITING.\n        if ((!currentState.equals(STATE_WAITING)) &&\n            (!currentState.equals(STATE_PAUSED))) {\n            return currentState;\n        }\n        \n        try {\n            List<FiredTriggerRecord> lst = getDelegate().selectFiredTriggerRecordsByJob(conn,\n                    jobKey.getName(), jobKey.getGroup());\n\n            if (!lst.isEmpty()) {\n                FiredTriggerRecord rec = lst.get(0);\n                if (rec.isJobDisallowsConcurrentExecution()) { // OLD_TODO: worry about failed/recovering/volatile job  states?\n                    return (STATE_PAUSED.equals(currentState)) ? STATE_PAUSED_BLOCKED : STATE_BLOCKED;\n                }\n            }\n\n            return currentState;\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                \"Couldn't determine if trigger should be in a blocked state '\"\n                    + jobKey + \"': \"\n                    + e.getMessage(), e);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link org.quartz.Trigger}</code> with the\n     * given name.\n     * </p>\n     * \n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseTrigger(TriggerKey)\n     */\n    public void resumeTrigger(final TriggerKey triggerKey) throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    resumeTrigger(conn, triggerKey);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link org.quartz.Trigger}</code> with the\n     * given name.\n     * </p>\n     * \n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseTrigger(Connection, TriggerKey)\n     */\n    public void resumeTrigger(Connection conn, \n            TriggerKey key)\n        throws JobPersistenceException {\n        try {\n\n            TriggerStatus status = getDelegate().selectTriggerStatus(conn,\n                    key);\n\n            if (status == null || status.getNextFireTime() == null) {\n                return;\n            }\n\n            boolean blocked = STATE_PAUSED_BLOCKED.equals(status.getStatus());\n\n            String newState = checkBlockedState(conn, status.getJobKey(), STATE_WAITING);\n\n            boolean misfired = false;\n\n            if (schedulerRunning && status.getNextFireTime().before(new Date())) {\n                misfired = updateMisfiredTrigger(conn, key,\n                    newState, true);\n            }\n\n            if(!misfired) {\n                if(blocked) {\n                    getDelegate().updateTriggerStateFromOtherState(conn,\n                            key, newState, STATE_PAUSED_BLOCKED);\n                } else {\n                    getDelegate().updateTriggerStateFromOtherState(conn,\n                            key, newState, STATE_PAUSED);\n                }\n            } \n\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't resume trigger '\"\n                    + key + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link org.quartz.Job}</code> with the\n     * given name.\n     * </p>\n     * \n     * <p>\n     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one\n     * or more fire-times, then the <code>Trigger</code>'s misfire\n     * instruction will be applied.\n     * </p>\n     * \n     * @see #pauseJob(JobKey)\n     */\n    public void resumeJob(final JobKey jobKey) throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    List<OperableTrigger> triggers = getTriggersForJob(conn, jobKey);\n                    for (OperableTrigger trigger: triggers) {\n                        resumeTrigger(conn, trigger.getKey());\n                    }\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link org.quartz.Job}s</code> in\n     * the given group.\n     * </p>\n     * \n     * <p>\n     * If any of the <code>Job</code> s had <code>Trigger</code> s that\n     * missed one or more fire-times, then the <code>Trigger</code>'s\n     * misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseJobs(org.quartz.impl.matchers.GroupMatcher)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> resumeJobs(final GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException {\n        return (Set<String>) executeInLock(\n            LOCK_TRIGGER_ACCESS,\n                (TransactionCallback) conn -> {\n                    Set<JobKey> jobKeys = getJobNames(conn, matcher);\n                    Set<String> groupNames = new HashSet<>();\n\n                    for (JobKey jobKey: jobKeys) {\n                        List<OperableTrigger> triggers = getTriggersForJob(conn, jobKey);\n                        for (OperableTrigger trigger: triggers) {\n                            resumeTrigger(conn, trigger.getKey());\n                        }\n                        groupNames.add(jobKey.getGroup());\n                    }\n                    return groupNames;\n                });\n    }\n    \n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.Trigger}s</code> matching the\n     * given groupMatcher.\n     * </p>\n     * \n     * @see #resumeTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> pauseTriggers(final GroupMatcher<TriggerKey> matcher)\n        throws JobPersistenceException {\n        return (Set<String>) executeInLock(\n            LOCK_TRIGGER_ACCESS,\n                (TransactionCallback) conn -> pauseTriggerGroup(conn, matcher));\n    }\n    \n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.Trigger}s</code> matching the\n     * given groupMatcher.\n     * </p>\n     * \n     * @see #resumeTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher)\n     */\n    public Set<String> pauseTriggerGroup(Connection conn,\n            GroupMatcher<TriggerKey> matcher) throws JobPersistenceException {\n\n        try {\n\n            getDelegate().updateTriggerGroupStateFromOtherStates(\n                    conn, matcher, STATE_PAUSED, STATE_ACQUIRED,\n                    STATE_WAITING, STATE_WAITING);\n\n            getDelegate().updateTriggerGroupStateFromOtherState(\n                    conn, matcher, STATE_PAUSED_BLOCKED, STATE_BLOCKED);\n\n            List<String> groups = getDelegate().selectTriggerGroups(conn, matcher);\n            \n            // make sure to account for an exact group match for a group that doesn't yet exist\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            if (operator.equals(StringOperatorName.EQUALS) && !groups.contains(matcher.getCompareToValue())) {\n              groups.add(matcher.getCompareToValue());\n            }\n\n            for (String group : groups) {\n                if (!getDelegate().isTriggerGroupPaused(conn, group)) {\n                    getDelegate().insertPausedTriggerGroup(conn, group);\n                }\n            }\n\n            return new HashSet<>(groups);\n\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't pause trigger group '\"\n                    + matcher + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> getPausedTriggerGroups() \n        throws JobPersistenceException {\n        return (Set<String>)executeWithoutLock( // no locks necessary for read...\n                (TransactionCallback) this::getPausedTriggerGroups);\n    }    \n    \n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.Trigger}s</code> in the\n     * given group.\n     * </p>\n     * \n     * @see #resumeTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    public Set<String> getPausedTriggerGroups(Connection conn) \n        throws JobPersistenceException {\n\n        try {\n            return getDelegate().selectPausedTriggerGroups(conn);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't determine paused trigger groups: \" + e.getMessage(), e);\n        }\n    }\n    \n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link org.quartz.Trigger}s</code>\n     * matching the given groupMatcher.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Set<String> resumeTriggers(final GroupMatcher<TriggerKey> matcher)\n        throws JobPersistenceException {\n        return (Set<String>) executeInLock(\n            LOCK_TRIGGER_ACCESS,\n                (TransactionCallback) conn -> resumeTriggerGroup(conn, matcher));\n\n    }\n    \n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link org.quartz.Trigger}s</code>\n     * matching the given groupMatcher.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    public Set<String> resumeTriggerGroup(Connection conn,\n            GroupMatcher<TriggerKey> matcher) throws JobPersistenceException {\n\n        try {\n\n            getDelegate().deletePausedTriggerGroup(conn, matcher);\n            HashSet<String> groups = new HashSet<>();\n\n            Set<TriggerKey> keys = getDelegate().selectTriggersInGroup(conn,\n                    matcher);\n\n            for (TriggerKey key: keys) {\n                resumeTrigger(conn, key);\n                groups.add(key.getGroup());\n            }\n\n            return groups;\n\n            // FUTURE_TODO: find an efficient way to resume triggers (better than the\n            // above)... logic below is broken because of\n            // findTriggersToBeBlocked()\n            /*\n             * int res =\n             * getDelegate().updateTriggerGroupStateFromOtherState(conn,\n             * groupName, STATE_WAITING, PAUSED);\n             * \n             * if(res > 0) {\n             * \n             * long misfireTime = System.currentTimeMillis();\n             * if(getMisfireThreshold() > 0) misfireTime -=\n             * getMisfireThreshold();\n             * \n             * Key[] misfires =\n             * getDelegate().selectMisfiredTriggersInGroupInState(conn,\n             * groupName, STATE_WAITING, misfireTime);\n             * \n             * List blockedTriggers = findTriggersToBeBlocked(conn,\n             * groupName);\n             * \n             * Iterator itr = blockedTriggers.iterator(); while(itr.hasNext()) {\n             * Key key = (Key)itr.next();\n             * getDelegate().updateTriggerState(conn, key.getName(),\n             * key.getGroup(), BLOCKED); }\n             * \n             * for(int i=0; i < misfires.length; i++) {               String\n             * newState = STATE_WAITING;\n             * if(blockedTriggers.contains(misfires[i])) newState =\n             * BLOCKED; updateMisfiredTrigger(conn,\n             * misfires[i].getName(), misfires[i].getGroup(), newState, true); } }\n             */\n\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't pause trigger group '\"\n                    + matcher + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     * \n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     * \n     * @see #resumeAll()\n     * @see #pauseTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher)\n     */\n    public void pauseAll() throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    pauseAll(conn);\n                }\n            });\n    }\n    \n    /**\n     * <p>\n     * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     * \n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     * \n     * @see #resumeAll(Connection)\n     * @see #pauseTriggerGroup(java.sql.Connection, org.quartz.impl.matchers.GroupMatcher)\n     */\n    public void pauseAll(Connection conn)\n        throws JobPersistenceException {\n\n        List<String> names = getTriggerGroupNames(conn);\n\n        for (String name: names) {\n            pauseTriggerGroup(conn, GroupMatcher.triggerGroupEquals(name));\n        }\n\n        try {\n            if (!getDelegate().isTriggerGroupPaused(conn, ALL_GROUPS_PAUSED)) {\n                getDelegate().insertPausedTriggerGroup(conn, ALL_GROUPS_PAUSED);\n            }\n\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't pause all trigger groups: \" + e.getMessage(), e);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseAll()\n     */\n    public void resumeAll()\n        throws JobPersistenceException {\n        executeInLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    resumeAll(conn);\n                }\n            });\n    }\n    \n    /**\n     * protected\n     * <p>\n     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     * \n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     * \n     * @see #pauseAll(Connection)\n     */\n    public void resumeAll(Connection conn)\n        throws JobPersistenceException {\n\n        List<String> names = getTriggerGroupNames(conn);\n\n        for (String name: names) {\n            resumeTriggerGroup(conn, GroupMatcher.triggerGroupEquals(name));\n        }\n\n        try {\n            getDelegate().deletePausedTriggerGroup(conn, ALL_GROUPS_PAUSED);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't resume all trigger groups: \" + e.getMessage(), e);\n        }\n    }\n\n    private static long ftrCtr = System.currentTimeMillis();\n\n    protected synchronized String getFiredTriggerRecordId() {\n        return getInstanceId() + ftrCtr++;\n    }\n\n    /**\n     * <p>\n     * Get a handle to the next N triggers to be fired, and mark them as 'reserved'\n     * by the calling scheduler.\n     * </p>\n     * \n     * @see #releaseAcquiredTrigger(OperableTrigger)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<OperableTrigger> acquireNextTriggers(final long noLaterThan, final int maxCount, final long timeWindow)\n        throws JobPersistenceException {\n        \n        String lockName;\n        if(isAcquireTriggersWithinLock() || maxCount > 1) { \n            lockName = LOCK_TRIGGER_ACCESS;\n        } else {\n            lockName = null;\n        }\n        return executeInNonManagedTXLock(lockName,\n                conn -> acquireNextTrigger(conn, noLaterThan, maxCount, timeWindow),\n                (conn, result) -> {\n                    try {\n                        List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());\n                        Set<String> fireInstanceIds = new HashSet<>();\n                        for (FiredTriggerRecord ft : acquired) {\n                            fireInstanceIds.add(ft.getFireInstanceId());\n                        }\n                        for (OperableTrigger tr : result) {\n                            if (fireInstanceIds.contains(tr.getFireInstanceId())) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    } catch (SQLException e) {\n                        throw new JobPersistenceException(\"error validating trigger acquisition\", e);\n                    }\n                });\n    }\n    \n    // FUTURE_TODO: this really ought to return something like a FiredTriggerBundle,\n    // so that the fireInstanceId doesn't have to be on the trigger...\n    protected List<OperableTrigger> acquireNextTrigger(Connection conn, long noLaterThan, int maxCount, long timeWindow)\n        throws JobPersistenceException {\n        if (timeWindow < 0) {\n          throw new IllegalArgumentException();\n        }\n        \n        List<OperableTrigger> acquiredTriggers = new ArrayList<>();\n        Set<JobKey> acquiredJobKeysForNoConcurrentExec = new HashSet<>();\n        final int MAX_DO_LOOP_RETRY = 3;\n        int currentLoopCount = 0;\n        do {\n            currentLoopCount ++;\n            try {\n                List<TriggerKey> keys = getDelegate().selectTriggerToAcquire(conn, noLaterThan + timeWindow, getMisfireTime(), maxCount);\n                \n                // No trigger is ready to fire yet.\n                if (keys == null || keys.isEmpty())\n                    return acquiredTriggers;\n\n                long batchEnd = noLaterThan;\n\n                for(TriggerKey triggerKey: keys) {\n                    // If our trigger is no longer available, try a new one.\n                    OperableTrigger nextTrigger = retrieveTrigger(conn, triggerKey);\n                    if(nextTrigger == null) {\n                        continue; // next trigger\n                    }\n                    \n                    // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then\n                    // put it back into the timeTriggers set and continue to search for next trigger.\n                    JobKey jobKey = nextTrigger.getJobKey();\n                    JobDetail job;\n                    try {\n                        job = retrieveJob(conn, jobKey);\n                    } catch (JobPersistenceException jpe) {\n                        try {\n                            getLog().error(\"Error retrieving job, setting trigger state to ERROR.\", jpe);\n                            getDelegate().updateTriggerState(conn, triggerKey, STATE_ERROR);\n                        } catch (SQLException sqle) {\n                            getLog().error(\"Unable to set trigger state to ERROR.\", sqle);\n                        }\n                        continue;\n                    }\n                    \n                    if (job.isConcurrentExecutionDisallowed()) {\n                        if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) {\n                            continue; // next trigger\n                        } else {\n                            acquiredJobKeysForNoConcurrentExec.add(jobKey);\n                        }\n                    }\n\n                    Date nextFireTime = nextTrigger.getNextFireTime();\n\n                    // A trigger should not return NULL on nextFireTime when fetched from DB.\n                    // But for whatever reason if we do have this (BAD trigger implementation or\n                    // data?), we then should log a warning and continue to next trigger.\n                    // User would need to manually fix these triggers from DB as they will not\n                    // able to be clean up by Quartz since we are not returning it to be processed.\n                    if (nextFireTime == null) {\n                        log.warn(\"Trigger {} returned null on nextFireTime and yet still exists in DB!\",\n                            nextTrigger.getKey());\n                        continue;\n                    }\n                    \n                    if (nextFireTime.getTime() > batchEnd) {\n                      break;\n                    }\n                    // We now have a acquired trigger, let's add to return list.\n                    // If our trigger was no longer in the expected state, try a new one.\n                    int rowsUpdated = getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, STATE_ACQUIRED, STATE_WAITING);\n                    if (rowsUpdated <= 0) {\n                        continue; // next trigger\n                    }\n                    nextTrigger.setFireInstanceId(getFiredTriggerRecordId());\n                    getDelegate().insertFiredTrigger(conn, nextTrigger, STATE_ACQUIRED, null);\n\n                    if(acquiredTriggers.isEmpty()) {\n                        batchEnd = Math.max(nextFireTime.getTime(), System.currentTimeMillis()) + timeWindow;\n                    }\n                    acquiredTriggers.add(nextTrigger);\n                }\n\n                // if we didn't end up with any trigger to fire from that first\n                // batch, try again for another batch. We allow with a max retry count.\n                if(acquiredTriggers.isEmpty() && currentLoopCount < MAX_DO_LOOP_RETRY) {\n                    continue;\n                }\n                \n                // We are done with the while loop.\n                break;\n            } catch (Exception e) {\n                throw new JobPersistenceException(\n                          \"Couldn't acquire next trigger: \" + e.getMessage(), e);\n            }\n        } while (true);\n        \n        // Return the acquired trigger list\n        return acquiredTriggers;\n    }\n    \n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler no longer plans to\n     * fire the given <code>Trigger</code>, that it had previously acquired\n     * (reserved).\n     * </p>\n     */\n    public void releaseAcquiredTrigger(final OperableTrigger trigger) {\n        retryExecuteInNonManagedTXLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    releaseAcquiredTrigger(conn, trigger);\n                }\n            });\n    }\n    \n    protected void releaseAcquiredTrigger(Connection conn,\n            OperableTrigger trigger)\n        throws JobPersistenceException {\n        try {\n            getDelegate().updateTriggerStateFromOtherState(conn,\n                    trigger.getKey(), STATE_WAITING, STATE_ACQUIRED);\n            getDelegate().updateTriggerStateFromOtherState(conn,\n                    trigger.getKey(), STATE_WAITING, STATE_BLOCKED);\n            getDelegate().deleteFiredTrigger(conn, trigger.getFireInstanceId());\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't release acquired trigger: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler is now firing the\n     * given <code>Trigger</code> (executing its associated <code>Job</code>),\n     * that it had previously acquired (reserved).\n     * </p>\n     * \n     * @return null if the trigger or its job or calendar no longer exist, or\n     *         if the trigger was not successfully put into the 'executing'\n     *         state.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<TriggerFiredResult> triggersFired(final List<OperableTrigger> triggers) throws JobPersistenceException {\n        return executeInNonManagedTXLock(LOCK_TRIGGER_ACCESS,\n                conn -> {\n                    List<TriggerFiredResult> results = new ArrayList<>();\n\n                    TriggerFiredResult result;\n                    for (OperableTrigger trigger : triggers) {\n                        try {\n                            TriggerFiredBundle bundle = triggerFired(conn, trigger);\n                            result = new TriggerFiredResult(bundle);\n                        } catch (JobPersistenceException | RuntimeException jpe) {\n                            result = new TriggerFiredResult(jpe);\n                        }\n                        results.add(result);\n                    }\n\n                    return results;\n                },\n                (conn, result) -> {\n                    try {\n                        List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());\n                        Set<String> executingTriggers = new HashSet<>();\n                        for (FiredTriggerRecord ft : acquired) {\n                            if (STATE_EXECUTING.equals(ft.getFireInstanceState())) {\n                                executingTriggers.add(ft.getFireInstanceId());\n                            }\n                        }\n                        for (TriggerFiredResult tr : result) {\n                            if (tr.getTriggerFiredBundle() != null && executingTriggers.contains(tr.getTriggerFiredBundle().getTrigger().getFireInstanceId())) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    } catch (SQLException e) {\n                        throw new JobPersistenceException(\"error validating trigger acquisition\", e);\n                    }\n                });\n    }\n\n    protected TriggerFiredBundle triggerFired(Connection conn,\n            OperableTrigger trigger)\n        throws JobPersistenceException {\n        JobDetail job;\n        Calendar cal = null;\n\n        // Make sure trigger wasn't deleted, paused, or completed...\n        try { // if trigger was deleted, state will be STATE_DELETED\n            String state = getDelegate().selectTriggerState(conn,\n                    trigger.getKey());\n            if (!state.equals(STATE_ACQUIRED)) {\n                return null;\n            }\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't select trigger state: \"\n                    + e.getMessage(), e);\n        }\n\n        try {\n            job = retrieveJob(conn, trigger.getJobKey());\n            if (job == null) { return null; }\n        } catch (JobPersistenceException jpe) {\n            try {\n                getLog().error(\"Error retrieving job, setting trigger state to ERROR.\", jpe);\n                getDelegate().updateTriggerState(conn, trigger.getKey(),\n                        STATE_ERROR);\n            } catch (SQLException sqle) {\n                getLog().error(\"Unable to set trigger state to ERROR.\", sqle);\n            }\n            throw jpe;\n        }\n\n        if (trigger.getCalendarName() != null) {\n            cal = retrieveCalendar(conn, trigger.getCalendarName());\n            if (cal == null) { return null; }\n        }\n\n        try {\n            getDelegate().updateFiredTrigger(conn, trigger, STATE_EXECUTING, job);\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't insert fired trigger: \"\n                    + e.getMessage(), e);\n        }\n\n        Date prevFireTime = trigger.getPreviousFireTime();\n\n        // call triggered - to update the trigger's next-fire-time state...\n        trigger.triggered(cal);\n\n        String state = STATE_WAITING;\n        boolean force = true;\n        \n        if (job.isConcurrentExecutionDisallowed()) {\n            state = STATE_BLOCKED;\n            force = false;\n            try {\n                getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),\n                        STATE_BLOCKED, STATE_WAITING);\n                getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),\n                        STATE_BLOCKED, STATE_ACQUIRED);\n                getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),\n                        STATE_PAUSED_BLOCKED, STATE_PAUSED);\n            } catch (SQLException e) {\n                throw new JobPersistenceException(\n                        \"Couldn't update states of blocked triggers: \"\n                                + e.getMessage(), e);\n            }\n        } \n            \n        if (trigger.getNextFireTime() == null) {\n            state = STATE_COMPLETE;\n            force = true;\n        }\n\n        storeTrigger(conn, trigger, job, true, state, force, false);\n\n        job.getJobDataMap().clearDirtyFlag();\n\n        return new TriggerFiredBundle(job, trigger, cal, trigger.getKey().getGroup()\n                .equals(Scheduler.DEFAULT_RECOVERY_GROUP), new Date(), trigger\n                .getPreviousFireTime(), prevFireTime, trigger.getNextFireTime());\n    }\n\n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler has completed the\n     * firing of the given <code>Trigger</code> (and the execution its\n     * associated <code>Job</code>), and that the <code>{@link org.quartz.JobDataMap}</code>\n     * in the given <code>JobDetail</code> should be updated if the <code>Job</code>\n     * is stateful.\n     * </p>\n     */\n    public void triggeredJobComplete(final OperableTrigger trigger,\n            final JobDetail jobDetail, final CompletedExecutionInstruction triggerInstCode) {\n        retryExecuteInNonManagedTXLock(\n            LOCK_TRIGGER_ACCESS,\n            new VoidTransactionCallback() {\n                public void executeVoid(Connection conn) throws JobPersistenceException {\n                    triggeredJobComplete(conn, trigger, jobDetail,triggerInstCode);\n                }\n            });    \n    }\n    \n    protected void triggeredJobComplete(Connection conn,\n            OperableTrigger trigger, JobDetail jobDetail,\n            CompletedExecutionInstruction triggerInstCode) throws JobPersistenceException {\n        try {\n            if (triggerInstCode == CompletedExecutionInstruction.DELETE_TRIGGER) {\n                if(trigger.getNextFireTime() == null) { \n                    // double check for possible reschedule within job \n                    // execution, which would cancel the need to delete...\n                    TriggerStatus stat = getDelegate().selectTriggerStatus(\n                            conn, trigger.getKey());\n                    if(stat != null && stat.getNextFireTime() == null) {\n                        removeTrigger(conn, trigger.getKey());\n                    }\n                } else{\n                    removeTrigger(conn, trigger.getKey());\n                    signalSchedulingChangeOnTxCompletion(0L);\n                }\n            } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) {\n                getDelegate().updateTriggerState(conn, trigger.getKey(),\n                        STATE_COMPLETE);\n                signalSchedulingChangeOnTxCompletion(0L);\n            } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_ERROR) {\n                getLog().info(\"Trigger {} set to ERROR state.\", trigger.getKey());\n                getDelegate().updateTriggerState(conn, trigger.getKey(),\n                        STATE_ERROR);\n                signalSchedulingChangeOnTxCompletion(0L);\n            } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) {\n                getDelegate().updateTriggerStatesForJob(conn,\n                        trigger.getJobKey(), STATE_COMPLETE);\n                signalSchedulingChangeOnTxCompletion(0L);\n            } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR) {\n                getLog().info(\"All triggers of Job {} set to ERROR state.\", trigger.getKey());\n                getDelegate().updateTriggerStatesForJob(conn,\n                        trigger.getJobKey(), STATE_ERROR);\n                signalSchedulingChangeOnTxCompletion(0L);\n            }\n\n            if (jobDetail.isConcurrentExecutionDisallowed()) {\n                getDelegate().updateTriggerStatesForJobFromOtherState(conn,\n                        jobDetail.getKey(), STATE_WAITING,\n                        STATE_BLOCKED);\n\n                getDelegate().updateTriggerStatesForJobFromOtherState(conn,\n                        jobDetail.getKey(), STATE_PAUSED,\n                        STATE_PAUSED_BLOCKED);\n\n                signalSchedulingChangeOnTxCompletion(0L);\n            }\n            if (jobDetail.isPersistJobDataAfterExecution()) {\n                try {\n                    if (jobDetail.getJobDataMap().isDirty()) {\n                        getDelegate().updateJobData(conn, jobDetail);\n                    }\n                } catch (IOException e) {\n                    throw new JobPersistenceException(\n                            \"Couldn't serialize job data: \" + e.getMessage(), e);\n                } catch (SQLException e) {\n                    throw new JobPersistenceException(\n                            \"Couldn't update job data: \" + e.getMessage(), e);\n                }\n            }\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\n                    \"Couldn't update trigger state(s): \" + e.getMessage(), e);\n        }\n\n        try {\n            getDelegate().deleteFiredTrigger(conn, trigger.getFireInstanceId());\n        } catch (SQLException e) {\n            throw new JobPersistenceException(\"Couldn't delete fired trigger: \"\n                    + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * <P>\n     * Get the driver delegate for DB operations.\n     * </p>\n     */\n    protected DriverDelegate getDelegate() throws NoSuchDelegateException {\n        synchronized(this) {\n            if(null == delegate) {\n                try {\n                    if(delegateClassName != null) {\n                        delegateClass = getClassLoadHelper().loadClass(delegateClassName, DriverDelegate.class);\n                    }\n\n                    delegate = delegateClass.getDeclaredConstructor().newInstance();\n\n                    delegate.initialize(getLog(), tablePrefix, instanceName, instanceId, getClassLoadHelper(), canUseProperties(), getDriverDelegateInitString());\n                    delegate.setUseEnhancedStatements(this.useEnhancedStatements);\n                } catch (InstantiationException | IllegalAccessException | NoSuchMethodException |\n                         InvocationTargetException e) {\n                    throw new NoSuchDelegateException(\"Couldn't create delegate: \"\n                            + e.getMessage(), e);\n                } catch (ClassNotFoundException e) {\n                    throw new NoSuchDelegateException(\"Couldn't load delegate class: \"\n                            + e.getMessage(), e);\n                }\n            }\n            return delegate;\n        }\n    }\n\n    protected Semaphore getLockHandler() {\n        return lockHandler;\n    }\n\n    public void setLockHandler(Semaphore lockHandler) {\n        this.lockHandler = lockHandler;\n    }\n\n    //---------------------------------------------------------------------------\n    // Management methods\n    //---------------------------------------------------------------------------\n\n    protected RecoverMisfiredJobsResult doRecoverMisfires() throws JobPersistenceException {\n        boolean transOwner = false;\n        Connection conn = getNonManagedTXConnection();\n        try {\n            RecoverMisfiredJobsResult result = RecoverMisfiredJobsResult.NO_OP;\n            \n            // Before we make the potentially expensive call to acquire the \n            // trigger lock, peek ahead to see if it is likely we would find\n            // misfired triggers requiring recovery.\n            int misfireCount = (getDoubleCheckLockMisfireHandler()) ?\n                getDelegate().countMisfiredTriggersInState(\n                    conn, STATE_WAITING, getMisfireTime()) : \n                Integer.MAX_VALUE;\n            \n            if (misfireCount == 0) {\n                getLog().debug(\n                    \"Found 0 triggers that missed their scheduled fire-time.\");\n            } else {\n                transOwner = getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS);\n                \n                result = recoverMisfiredJobs(conn, false);\n            }\n            \n            commitConnection(conn);\n            return result;\n        } catch (JobPersistenceException e) {\n            rollbackConnection(conn);\n            throw e;\n        } catch (SQLException e) {\n            rollbackConnection(conn);\n            throw new JobPersistenceException(\"Database error recovering from misfires.\", e);\n        } catch (RuntimeException e) {\n            rollbackConnection(conn);\n            throw new JobPersistenceException(\"Unexpected runtime exception: \"\n                    + e.getMessage(), e);\n        } finally {\n            try {\n                releaseLock(LOCK_TRIGGER_ACCESS, transOwner);\n            } finally {\n                cleanupConnection(conn);\n            }\n        }\n    }\n\n    protected final ThreadLocal<Long> sigChangeForTxCompletion = new ThreadLocal<>();\n    protected void signalSchedulingChangeOnTxCompletion(long candidateNewNextFireTime) {\n        Long sigTime = sigChangeForTxCompletion.get();\n        if(sigTime == null && candidateNewNextFireTime >= 0L)\n            sigChangeForTxCompletion.set(candidateNewNextFireTime);\n        else {\n            if(sigTime == null || candidateNewNextFireTime < sigTime)\n                sigChangeForTxCompletion.set(candidateNewNextFireTime);\n        }\n    }\n    \n    protected Long clearAndGetSignalSchedulingChangeOnTxCompletion() {\n        Long t = sigChangeForTxCompletion.get();\n        sigChangeForTxCompletion.set(null);\n        return t;\n    }\n\n    protected void signalSchedulingChangeImmediately(long candidateNewNextFireTime) {\n        schedSignaler.signalSchedulingChange(candidateNewNextFireTime);\n    }\n\n    //---------------------------------------------------------------------------\n    // Cluster management methods\n    //---------------------------------------------------------------------------\n\n    protected boolean firstCheckIn = true;\n\n    protected long lastCheckin = System.currentTimeMillis();\n    \n    protected boolean doCheckin() throws JobPersistenceException {\n        boolean transOwner = false;\n        boolean transStateOwner = false;\n        boolean recovered = false;\n\n        Connection conn = getNonManagedTXConnection();\n        try {\n            // Other than the first time, always checkin first to make sure there is \n            // work to be done before we acquire the lock (since that is expensive, \n            // and is almost never necessary).  This must be done in a separate\n            // transaction to prevent a deadlock under recovery conditions.\n            List<SchedulerStateRecord> failedRecords = null;\n            if (!firstCheckIn) {\n                failedRecords = clusterCheckIn(conn);\n                commitConnection(conn);\n            }\n            \n            if (firstCheckIn || (!failedRecords.isEmpty())) {\n                getLockHandler().obtainLock(conn, LOCK_STATE_ACCESS);\n                transStateOwner = true;\n    \n                // Now that we own the lock, make sure we still have work to do. \n                // The first time through, we also need to make sure we update/create our state record\n                failedRecords = (firstCheckIn) ? clusterCheckIn(conn) : findFailedInstances(conn);\n    \n                if (!failedRecords.isEmpty()) {\n                    getLockHandler().obtainLock(conn, LOCK_TRIGGER_ACCESS);\n                    //getLockHandler().obtainLock(conn, LOCK_JOB_ACCESS);\n                    transOwner = true;\n    \n                    clusterRecover(conn, failedRecords);\n                    recovered = true;\n                }\n            }\n            \n            commitConnection(conn);\n        } catch (JobPersistenceException e) {\n            rollbackConnection(conn);\n            throw e;\n        } finally {\n            try {\n                releaseLock(LOCK_TRIGGER_ACCESS, transOwner);\n            } finally {\n                try {\n                    releaseLock(LOCK_STATE_ACCESS, transStateOwner);\n                } finally {\n                    cleanupConnection(conn);\n                }\n            }\n        }\n\n        firstCheckIn = false;\n\n        return recovered;\n    }\n\n    /**\n     * Get a list of all scheduler instances in the cluster that may have failed.\n     * This includes this scheduler if it is checking in for the first time.\n     */\n    protected List<SchedulerStateRecord> findFailedInstances(Connection conn)\n        throws JobPersistenceException {\n        try {\n            List<SchedulerStateRecord> failedInstances = new LinkedList<>();\n            boolean foundThisScheduler = false;\n            long timeNow = System.currentTimeMillis();\n            \n            List<SchedulerStateRecord> states = getDelegate().selectSchedulerStateRecords(conn, null);\n\n            for(SchedulerStateRecord rec: states) {\n        \n                // find own record...\n                if (rec.getSchedulerInstanceId().equals(getInstanceId())) {\n                    foundThisScheduler = true;\n                    if (firstCheckIn) {\n                        failedInstances.add(rec);\n                    }\n                } else {\n                    // find failed instances...\n                    if (calcFailedIfAfter(rec) < timeNow) {\n                        failedInstances.add(rec);\n                    }\n                }\n            }\n            \n            // The first time through, also check for orphaned fired triggers.\n            if (firstCheckIn) {\n                failedInstances.addAll(findOrphanedFailedInstances(conn, states));\n            }\n            \n            // If not the first time but we didn't find our own instance, then\n            // Someone must have done recovery for us.\n            if ((!foundThisScheduler) && (!firstCheckIn)) {\n                // FUTURE_TODO: revisit when handle self-failed-out impl'ed (see FUTURE_TODO in clusterCheckIn() below)\n                getLog().warn(\"This scheduler instance ({}) is still active but was recovered by another instance in the cluster.  This may cause inconsistent behavior.\", getInstanceId());\n            }\n            \n            return failedInstances;\n        } catch (Exception e) {\n            lastCheckin = System.currentTimeMillis();\n            throw new JobPersistenceException(\"Failure identifying failed instances when checking-in: \"\n                    + e.getMessage(), e);\n        }\n    }\n    \n    /**\n     * Create dummy <code>SchedulerStateRecord</code> objects for fired triggers\n     * that have no scheduler state record.  Checkin timestamp and interval are\n     * left as zero on these dummy <code>SchedulerStateRecord</code> objects.\n     * \n     * @param schedulerStateRecords List of all current <code>SchedulerStateRecords</code>\n     */\n    private List<SchedulerStateRecord> findOrphanedFailedInstances(\n            Connection conn, \n            List<SchedulerStateRecord> schedulerStateRecords) \n        throws SQLException, NoSuchDelegateException {\n        List<SchedulerStateRecord> orphanedInstances = new ArrayList<>();\n        \n        Set<String> allFiredTriggerInstanceNames = getDelegate().selectFiredTriggerInstanceNames(conn);\n        if (!allFiredTriggerInstanceNames.isEmpty()) {\n            for (SchedulerStateRecord rec: schedulerStateRecords) {\n                \n                allFiredTriggerInstanceNames.remove(rec.getSchedulerInstanceId());\n            }\n            \n            for (String inst: allFiredTriggerInstanceNames) {\n                \n                SchedulerStateRecord orphanedInstance = new SchedulerStateRecord();\n                orphanedInstance.setSchedulerInstanceId(inst);\n                \n                orphanedInstances.add(orphanedInstance);\n\n                getLog().warn(\"Found orphaned fired triggers for instance: {}\", orphanedInstance.getSchedulerInstanceId());\n            }\n        }\n        \n        return orphanedInstances;\n    }\n    \n    protected long calcFailedIfAfter(SchedulerStateRecord rec) {\n        return rec.getCheckinTimestamp() +\n            Math.max(rec.getCheckinInterval(), \n                    (System.currentTimeMillis() - lastCheckin)) +\n            7500L;\n    }\n    \n    protected List<SchedulerStateRecord> clusterCheckIn(Connection conn)\n        throws JobPersistenceException {\n\n        List<SchedulerStateRecord> failedInstances = findFailedInstances(conn);\n        \n        try {\n            // FUTURE_TODO: handle self-failed-out\n\n            // check in...\n            lastCheckin = System.currentTimeMillis();\n            if(getDelegate().updateSchedulerState(conn, getInstanceId(), lastCheckin) == 0) {\n                getDelegate().insertSchedulerState(conn, getInstanceId(),\n                        lastCheckin, getClusterCheckinInterval());\n            }\n            \n        } catch (Exception e) {\n            throw new JobPersistenceException(\"Failure updating scheduler state when checking-in: \"\n                    + e.getMessage(), e);\n        }\n\n        return failedInstances;\n    }\n\n    @SuppressWarnings(\"ConstantConditions\")\n    protected void clusterRecover(Connection conn, List<SchedulerStateRecord> failedInstances)\n        throws JobPersistenceException {\n\n        if (!failedInstances.isEmpty()) {\n\n            long recoverIds = System.currentTimeMillis();\n\n            logWarnIfNonZero(failedInstances.size(),\n                    \"ClusterManager: detected \" + failedInstances.size()\n                            + \" failed or restarted instances.\");\n            try {\n                for (SchedulerStateRecord rec : failedInstances) {\n                    getLog().info(\"ClusterManager: Scanning for instance \\\"{}\\\"'s failed in-progress jobs.\", rec.getSchedulerInstanceId());\n\n                    List<FiredTriggerRecord> firedTriggerRecs = getDelegate()\n                            .selectInstancesFiredTriggerRecords(conn,\n                                    rec.getSchedulerInstanceId());\n\n                    int acquiredCount = 0;\n                    int recoveredCount = 0;\n                    int otherCount = 0;\n\n                    Set<TriggerKey> triggerKeys = new HashSet<>();\n\n                    for (FiredTriggerRecord ftRec : firedTriggerRecs) {\n\n                        TriggerKey tKey = ftRec.getTriggerKey();\n                        JobKey jKey = ftRec.getJobKey();\n\n                        triggerKeys.add(tKey);\n\n                        // release blocked triggers..\n                        if (ftRec.getFireInstanceState().equals(STATE_BLOCKED)) {\n                            getDelegate()\n                                    .updateTriggerStatesForJobFromOtherState(\n                                            conn, jKey,\n                                            STATE_WAITING, STATE_BLOCKED);\n                        } else if (ftRec.getFireInstanceState().equals(STATE_PAUSED_BLOCKED)) {\n                            getDelegate()\n                                    .updateTriggerStatesForJobFromOtherState(\n                                            conn, jKey,\n                                            STATE_PAUSED, STATE_PAUSED_BLOCKED);\n                        }\n\n                        // release acquired triggers..\n                        if (ftRec.getFireInstanceState().equals(STATE_ACQUIRED)) {\n                            getDelegate().updateTriggerStateFromOtherState(\n                                    conn, tKey, STATE_WAITING,\n                                    STATE_ACQUIRED);\n                            acquiredCount++;\n                        } else if (ftRec.isJobRequestsRecovery()) {\n                            // handle jobs marked for recovery that were not fully\n                            // executed..\n                            if (jobExists(conn, jKey)) {\n                                @SuppressWarnings(\"deprecation\")\n                                SimpleTriggerImpl rcvryTrig = new SimpleTriggerImpl(\n                                        \"recover_\"\n                                                + rec.getSchedulerInstanceId()\n                                                + \"_\"\n                                                + recoverIds++,\n                                        Scheduler.DEFAULT_RECOVERY_GROUP,\n                                        new Date(ftRec.getScheduleTimestamp()));\n                                rcvryTrig.setJobName(jKey.getName());\n                                rcvryTrig.setJobGroup(jKey.getGroup());\n                                rcvryTrig.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n                                rcvryTrig.setPriority(ftRec.getPriority());\n                                JobDataMap jd = getDelegate().selectTriggerJobDataMap(conn, tKey.getName(), tKey.getGroup());\n                                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME, tKey.getName());\n                                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP, tKey.getGroup());\n                                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS, String.valueOf(ftRec.getFireTimestamp()));\n                                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS, String.valueOf(ftRec.getScheduleTimestamp()));\n                                rcvryTrig.setJobDataMap(jd);\n\n                                rcvryTrig.computeFirstFireTime(null);\n                                storeTrigger(conn, rcvryTrig, null, false,\n                                        STATE_WAITING, false, true);\n                                recoveredCount++;\n                            } else {\n                                getLog()\n                                        .warn(\"ClusterManager: failed job '{}' no longer exists, cannot schedule recovery.\", jKey);\n                                otherCount++;\n                            }\n                        } else {\n                            otherCount++;\n                        }\n\n                        // free up stateful job's triggers\n                        if (ftRec.isJobDisallowsConcurrentExecution()) {\n                            getDelegate()\n                                    .updateTriggerStatesForJobFromOtherState(\n                                            conn, jKey,\n                                            STATE_WAITING, STATE_BLOCKED);\n                            getDelegate()\n                                    .updateTriggerStatesForJobFromOtherState(\n                                            conn, jKey,\n                                            STATE_PAUSED, STATE_PAUSED_BLOCKED);\n                        }\n                    }\n\n                    getDelegate().deleteFiredTriggers(conn,\n                            rec.getSchedulerInstanceId());\n\n                    // Check if any of the fired triggers we just deleted were the last fired trigger\n                    // records of a COMPLETE trigger.\n                    int completeCount = 0;\n                    for (TriggerKey triggerKey : triggerKeys) {\n\n                        if (getDelegate().selectTriggerState(conn, triggerKey).\n                                equals(STATE_COMPLETE)) {\n                            List<FiredTriggerRecord> firedTriggers =\n                                    getDelegate().selectFiredTriggerRecords(conn, triggerKey.getName(), triggerKey.getGroup());\n                            if (firedTriggers.isEmpty()) {\n\n                                if (removeTrigger(conn, triggerKey)) {\n                                    completeCount++;\n                                }\n                            }\n                        }\n                    }\n\n                    logWarnIfNonZero(acquiredCount,\n                            \"ClusterManager: ......Freed \" + acquiredCount\n                                    + \" acquired trigger(s).\");\n                    logWarnIfNonZero(completeCount,\n                            \"ClusterManager: ......Deleted \" + completeCount\n                                    + \" complete triggers(s).\");\n                    logWarnIfNonZero(recoveredCount,\n                            \"ClusterManager: ......Scheduled \" + recoveredCount\n                                    + \" recoverable job(s) for recovery.\");\n                    logWarnIfNonZero(otherCount,\n                            \"ClusterManager: ......Cleaned-up \" + otherCount\n                                    + \" other failed job(s).\");\n\n                    if (!rec.getSchedulerInstanceId().equals(getInstanceId())) {\n                        getDelegate().deleteSchedulerState(conn,\n                                rec.getSchedulerInstanceId());\n                    }\n                }\n            } catch (Throwable e) {\n                throw new JobPersistenceException(\"Failure recovering jobs: \"\n                        + e.getMessage(), e);\n            }\n        }\n    }\n\n    protected void logWarnIfNonZero(int val, String warning) {\n        if (val > 0) {\n            getLog().info(warning);\n        } else {\n            getLog().debug(warning);\n        }\n    }\n\n    /**\n     * <p>\n     * Cleanup the given database connection.  This means restoring\n     * any modified auto commit or transaction isolation connection\n     * attributes, and then closing the underlying connection.\n     * </p>\n     * \n     * <p>\n     * This is separate from closeConnection() because the Spring \n     * integration relies on being able to overload closeConnection() and\n     * expects the same connection back that it originally returned\n     * from the datasource. \n     * </p>\n     * \n     * @see #closeConnection(Connection)\n     */\n    protected void cleanupConnection(Connection conn) {\n        if (conn != null) {\n            if (conn instanceof Proxy) {\n                Proxy connProxy = (Proxy)conn;\n                \n                InvocationHandler invocationHandler =\n                    Proxy.getInvocationHandler(connProxy);\n                if (invocationHandler instanceof AttributeRestoringConnectionInvocationHandler) {\n                    AttributeRestoringConnectionInvocationHandler connHandler =\n                        (AttributeRestoringConnectionInvocationHandler)invocationHandler;\n                        \n                    connHandler.restoreOriginalAttributes();\n                    closeConnection(connHandler.getWrappedConnection());\n                    return;\n                }\n            }\n            \n            // Wasn't a Proxy, or was a Proxy, but wasn't ours.\n            closeConnection(conn);\n        }\n    }\n    \n    \n    /**\n     * Closes the supplied <code>Connection</code>.\n     * <p>\n     * Ignores a <code>null Connection</code>.  \n     * Any exception thrown trying to close the <code>Connection</code> is\n     * logged and ignored.  \n     * </p>\n     * \n     * @param conn The <code>Connection</code> to close (Optional).\n     */\n    protected void closeConnection(Connection conn) {\n        if (conn != null) {\n            try {\n                conn.close();\n            } catch (SQLException e) {\n                getLog().error(\"Failed to close Connection\", e);\n            } catch (Throwable e) {\n                getLog().error(\n                    \"Unexpected exception closing Connection.\" +\n                    \"  This is often due to a Connection being returned after or during shutdown.\", e);\n            }\n        }\n    }\n\n    /**\n     * Rollback the supplied connection.\n     * \n     * <p>  \n     * Logs any SQLException it gets trying to rollback, but will not propagate\n     * the exception lest it mask the exception that caused the caller to \n     * need to rollback in the first place.\n     * </p>\n     *\n     * @param conn (Optional)\n     */\n    protected void rollbackConnection(Connection conn) {\n        if (conn != null) {\n            try {\n                conn.rollback();\n            } catch (SQLException e) {\n                getLog().error(\"Couldn't rollback jdbc connection. {}\", e.getMessage(), e);\n            }\n        }\n    }\n    \n    /**\n     * Commit the supplied connection\n     *\n     * @param conn (Optional)\n     * @throws JobPersistenceException thrown if a SQLException occurs when the\n     * connection is committed\n     */\n    protected void commitConnection(Connection conn)\n        throws JobPersistenceException {\n\n        if (conn != null) {\n            try {\n                conn.commit();\n            } catch (SQLException e) {\n                throw new JobPersistenceException(\n                    \"Couldn't commit jdbc connection. \"+e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * Returns true if enhanced statements for the database operations is enabled\n     * @return true if using enhanced statements\n     */\n    public boolean isUsingEnhancedStatements() {\n        return this.useEnhancedStatements;\n    }\n\n    /**\n     * Set to true to use enhanced bulk statements for the database operations\n     *\n     * @param useEnhancedStatements true to use enhanced statements\n     */\n    public void setUseEnhancedStatements(boolean useEnhancedStatements) {\n        this.useEnhancedStatements = useEnhancedStatements;\n        if (delegate != null) {\n            delegate.setUseEnhancedStatements(useEnhancedStatements);\n        }\n    }\n\n    /**\n     * Implement this interface to provide the code to execute within\n     * the a transaction template.  If no return value is required, execute\n     * should just return null.\n     * \n     * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback, TransactionValidator)\n     * @see JobStoreSupport#executeInLock(String, TransactionCallback)\n     * @see JobStoreSupport#executeWithoutLock(TransactionCallback)\n     */\n    protected interface TransactionCallback<T> {\n        T execute(Connection conn) throws JobPersistenceException;\n    }\n\n    protected interface TransactionValidator<T> {\n        Boolean validate(Connection conn, T result) throws JobPersistenceException;\n    }\n    \n    /**\n     * Implement this interface to provide the code to execute within\n     * the a transaction template that has no return value.\n     * \n     * @see JobStoreSupport#executeInNonManagedTXLock(String, TransactionCallback, TransactionValidator)\n     */\n    protected abstract class VoidTransactionCallback implements TransactionCallback<Void> {\n        public final Void execute(Connection conn) throws JobPersistenceException {\n            executeVoid(conn);\n            return null;\n        }\n        \n        abstract void executeVoid(Connection conn) throws JobPersistenceException;\n    }\n\n    /**\n     * Execute the given callback in a transaction. Depending on the JobStore, \n     * the surrounding transaction may be assumed to be already present \n     * (managed).  \n     * \n     * <p>\n     * This method just forwards to executeInLock() with a null lockName.\n     * </p>\n     * \n     * @see #executeInLock(String, TransactionCallback)\n     */\n    public <T> T executeWithoutLock(\n        TransactionCallback<T> txCallback) throws JobPersistenceException {\n        return executeInLock(null, txCallback);\n    }\n\n    /**\n     * Execute the given callback having acquired the given lock.\n     * Depending on the JobStore, the surrounding transaction may be \n     * assumed to be already present (managed).\n     * \n     * @param lockName The name of the lock to acquire, for example\n     * \"TRIGGER_ACCESS\".  If null, then no lock is acquired, but the\n     * lockCallback is still executed in a transaction. \n     */\n    protected abstract <T> T executeInLock(\n        String lockName, \n        TransactionCallback<T> txCallback) throws JobPersistenceException;\n    \n    protected <T> T retryExecuteInNonManagedTXLock(String lockName, TransactionCallback<T> txCallback) {\n        for (int retry = 1; !shutdown; retry++) {\n            try {\n                return executeInNonManagedTXLock(lockName, txCallback, null);\n            } catch (JobPersistenceException jpe) {\n                if(retry % 4 == 0) {\n                    schedSignaler.notifySchedulerListenersError(\"An error occurred while \" + txCallback, jpe);\n                }\n            } catch (RuntimeException e) {\n                getLog().error(\"retryExecuteInNonManagedTXLock: RuntimeException {}\", e.getMessage(), e);\n            }\n            try {\n                Thread.sleep(getDbRetryInterval()); // retry every N seconds (the db connection must be failed)\n            } catch (InterruptedException e) {\n                throw new IllegalStateException(\"Received interrupted exception\", e);\n            }\n        }\n        throw new IllegalStateException(\"JobStore is shutdown - aborting retry\");\n    }\n    \n    /**\n     * Execute the given callback having optionally acquired the given lock.\n     * This uses the non-managed transaction connection.\n     * \n     * @param lockName The name of the lock to acquire, for example\n     * \"TRIGGER_ACCESS\".  If null, then no lock is acquired, but the\n     * lockCallback is still executed in a non-managed transaction. \n     */\n    protected <T> T executeInNonManagedTXLock(\n            String lockName, \n            TransactionCallback<T> txCallback, final TransactionValidator<T> txValidator) throws JobPersistenceException {\n        boolean transOwner = false;\n        Connection conn = null;\n        try {\n            if (lockName != null) {\n                // If we aren't using db locks, then delay getting DB connection \n                // until after acquiring the lock since it isn't needed.\n                if (getLockHandler().requiresConnection()) {\n                    conn = getNonManagedTXConnection();\n                }\n                \n                transOwner = getLockHandler().obtainLock(conn, lockName);\n            }\n            \n            if (conn == null) {\n                conn = getNonManagedTXConnection();\n            }\n            \n            final T result = txCallback.execute(conn);\n            try {\n                commitConnection(conn);\n            } catch (JobPersistenceException e) {\n                rollbackConnection(conn);\n                if (txValidator == null || !retryExecuteInNonManagedTXLock(lockName, conn1 -> txValidator.validate(conn1, result))) {\n                    throw e;\n                }\n            }\n\n            Long sigTime = clearAndGetSignalSchedulingChangeOnTxCompletion();\n            if(sigTime != null && sigTime >= 0) {\n                signalSchedulingChangeImmediately(sigTime);\n            }\n            \n            return result;\n        } catch (JobPersistenceException e) {\n            rollbackConnection(conn);\n            throw e;\n        } catch (RuntimeException e) {\n            rollbackConnection(conn);\n            throw new JobPersistenceException(\"Unexpected runtime exception: \"\n                    + e.getMessage(), e);\n        } finally {\n            try {\n                releaseLock(lockName, transOwner);\n            } finally {\n                cleanupConnection(conn);\n            }\n        }\n    }\n    \n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // ClusterManager Thread\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class ClusterManager extends Thread {\n\n        private volatile boolean shutdown = false;\n\n        private int numFails = 0;\n        \n        ClusterManager() {\n            this.setPriority(Thread.NORM_PRIORITY + 2);\n            this.setName(\"QuartzScheduler_\" + instanceName + \"-\" + instanceId + \"_ClusterManager\");\n            this.setDaemon(getMakeThreadsDaemons());\n        }\n\n        public void initialize() {\n            this.manage();\n\n            ThreadExecutor executor = getThreadExecutor();\n            executor.execute(ClusterManager.this);\n        }\n\n        public void shutdown() {\n            shutdown = true;\n            this.interrupt();\n        }\n\n        private boolean manage() {\n            boolean res = false;\n            try {\n\n                res = doCheckin();\n\n                numFails = 0;\n                getLog().debug(\"ClusterManager: Check-in complete.\");\n            } catch (Exception e) {\n                if(numFails % 4 == 0) {\n                    getLog().error(\"ClusterManager: Error managing cluster: {}\", e.getMessage(), e);\n                }\n                numFails++;\n            }\n            return res;\n        }\n\n        @Override\n        public void run() {\n            while (!shutdown) {\n\n                if (!shutdown) {\n                    long timeToSleep = getClusterCheckinInterval();\n                    long transpiredTime = (System.currentTimeMillis() - lastCheckin);\n                    timeToSleep = timeToSleep - transpiredTime;\n                    if (timeToSleep <= 0) {\n                        timeToSleep = 100L;\n                    }\n\n                    if(numFails > 0) {\n                        timeToSleep = Math.max(getDbRetryInterval(), timeToSleep);\n                    }\n                    \n                    try {\n                        Thread.sleep(timeToSleep);\n                    } catch (Exception ignore) {\n                    }\n                }\n\n                if (!shutdown && this.manage()) {\n                    signalSchedulingChangeImmediately(0L);\n                }\n\n            }//while !shutdown\n        }\n    }\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // MisfireHandler Thread\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class MisfireHandler extends Thread {\n\n        private volatile boolean shutdown = false;\n\n        private int numFails = 0;\n        \n\n        MisfireHandler() {\n            this.setName(\"QuartzScheduler_\" + instanceName + \"-\" + instanceId + \"_MisfireHandler\");\n            this.setDaemon(getMakeThreadsDaemons());\n        }\n\n        public void initialize() {\n            ThreadExecutor executor = getThreadExecutor();\n            executor.execute(MisfireHandler.this);\n        }\n\n        public void shutdown() {\n            shutdown = true;\n            this.interrupt();\n        }\n\n        private RecoverMisfiredJobsResult manage() {\n            try {\n                getLog().debug(\"MisfireHandler: scanning for misfires...\");\n\n                RecoverMisfiredJobsResult res = doRecoverMisfires();\n                numFails = 0;\n                return res;\n            } catch (Exception e) {\n                if(numFails % 4 == 0) {\n                    getLog().error(\"MisfireHandler: Error handling misfires: {}\", e.getMessage(), e);\n                }\n                numFails++;\n            }\n            return RecoverMisfiredJobsResult.NO_OP;\n        }\n\n        @Override\n        public void run() {\n            \n            while (!shutdown) {\n\n                long sTime = System.currentTimeMillis();\n\n                RecoverMisfiredJobsResult recoverMisfiredJobsResult = manage();\n\n                if (recoverMisfiredJobsResult.getProcessedMisfiredTriggerCount() > 0) {\n                    signalSchedulingChangeImmediately(recoverMisfiredJobsResult.getEarliestNewTime());\n                }\n\n                if (!shutdown) {\n                    long timeToSleep = 50L;  // At least a short pause to help balance threads\n                    if (!recoverMisfiredJobsResult.hasMoreMisfiredTriggers()) {\n                        timeToSleep = getMisfireThreshold() - (System.currentTimeMillis() - sTime);\n                        if (timeToSleep <= 0) {\n                            timeToSleep = 50L;\n                        }\n\n                        if(numFails > 0) {\n                            timeToSleep = Math.max(getDbRetryInterval(), timeToSleep);\n                        }\n                    }\n                    \n                    try {\n                        Thread.sleep(timeToSleep);\n                    } catch (Exception ignore) {\n                    }\n                }//while !shutdown\n            }\n        }\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/JobStoreTX.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\n\nimport org.quartz.JobPersistenceException;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.impl.jdbcjobstore.JobStoreSupport;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerSignaler;\n\n/**\n * <p>\n * <code>JobStoreTX</code> is meant to be used in a standalone environment.\n * Both commit and rollback will be handled by this class.\n * </p>\n * \n * <p>\n * If you need a <code>{@link org.quartz.spi.JobStore}</code> class to use\n * within an application-server environment, use <code>{@link\n * org.quartz.impl.jdbcjobstore.JobStoreCMT}</code>\n * instead.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n */\npublic class JobStoreTX extends JobStoreSupport {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    @Override\n    public void initialize(ClassLoadHelper classLoadHelper,\n            SchedulerSignaler schedSignaler) throws SchedulerConfigException {\n\n        super.initialize(classLoadHelper, schedSignaler);\n\n        getLog().info(\"JobStoreTX initialized.\");\n    }\n\n    /**\n     * For <code>JobStoreTX</code>, the non-managed TX connection is just \n     * the normal connection because it is not CMT.\n     * \n     * @see JobStoreSupport#getConnection()\n     */\n    @Override\n    protected Connection getNonManagedTXConnection()\n        throws JobPersistenceException {\n        return getConnection();\n    }\n    \n    /**\n     * Execute the given callback having optionally acquired the given lock.\n     * For <code>JobStoreTX</code>, because it manages its own transactions\n     * and only has the one datasource, this is the same behavior as \n     * executeInNonManagedTXLock().\n     * \n     * @param lockName The name of the lock to acquire, for example \n     * \"TRIGGER_ACCESS\".  If null, then no lock is acquired, but the\n     * lockCallback is still executed in a transaction.\n     * \n     * @see JobStoreSupport#executeInNonManagedTXLock(java.lang.String, org.quartz.impl.jdbcjobstore.JobStoreSupport.TransactionCallback, org.quartz.impl.jdbcjobstore.JobStoreSupport.TransactionValidator) \n     * @see JobStoreCMT#executeInLock(String, TransactionCallback)\n     * @see JobStoreSupport#getNonManagedTXConnection()\n     * @see JobStoreSupport#getConnection()\n     */\n    @Override\n    protected Object executeInLock(\n            String lockName, \n            TransactionCallback txCallback) throws JobPersistenceException {\n        return executeInNonManagedTXLock(lockName, txCallback, null);\n    }\n}\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/LockException.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.JobPersistenceException;\n\n/**\n * <p>\n * Exception class for when there is a failure obtaining or releasing a\n * resource lock.\n * </p>\n * \n * @see Semaphore\n * \n * @author James House\n */\npublic class LockException extends JobPersistenceException {\n\n    private static final long serialVersionUID = 3993800462589137228L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public LockException(String msg) {\n        super(msg);\n    }\n\n    public LockException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/MSSQLDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport static org.quartz.TriggerKey.triggerKey;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.math.BigDecimal;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.quartz.TriggerKey;\n\n/**\n * <p>\n * This is a driver delegate for the MSSQL JDBC driver.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class MSSQLDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        InputStream binaryInput = rs.getBinaryStream(colName);\n\n        if(binaryInput == null || binaryInput.available() == 0) {\n            return null;\n        }\n\n        Object obj;\n\n        try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n            obj = in.readObject();\n        }\n\n        return obj;\n    }\n\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            return rs.getBinaryStream(colName);\n        }\n        return getObjectFromBlob(rs, colName);\n    }\n    \n    @Override\n    public List<TriggerKey> selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan, int maxCount)\n            throws SQLException {\n        // Set max rows to retrieve\n        if (maxCount < 1)\n            maxCount = 1; // we want at least one trigger back.\n        String selectTriggerToAcquire = \"SELECT TOP \" + maxCount + \" \" + SELECT_NEXT_TRIGGER_TO_ACQUIRE.substring(6);\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        List<TriggerKey> nextTriggers = new LinkedList<>();\n        try {\n            ps = conn.prepareStatement(rtp(selectTriggerToAcquire));\n            \n            ps.setMaxRows(maxCount);\n            \n            // Try to give jdbc driver a hint to hopefully not pull over more than the few rows we actually need.\n            // Note: in some jdbc drivers, such as MySQL, you must set maxRows before fetchSize, or you get exception!\n            ps.setFetchSize(maxCount);\n            \n            ps.setString(1, STATE_WAITING);\n            ps.setBigDecimal(2, new BigDecimal(String.valueOf(noLaterThan)));\n            ps.setBigDecimal(3, new BigDecimal(String.valueOf(noEarlierThan)));\n            rs = ps.executeQuery();\n            \n            while (rs.next() && nextTriggers.size() < maxCount) {\n                nextTriggers.add(triggerKey(\n                        rs.getString(COL_TRIGGER_NAME),\n                        rs.getString(COL_TRIGGER_GROUP)));\n            }\n            \n            return nextTriggers;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }      \n    }\n    \n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/NoRecordFoundException.java",
    "content": "package org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.TriggerKey;\n\npublic class NoRecordFoundException extends IllegalStateException {\n\n    private static final long serialVersionUID = 1L;\n    private final TriggerKey triggerKey;\n    private final String scheduleName;\n    private final String statement;\n    private final Class<?> delegateClass;\n\n    public NoRecordFoundException(TriggerKey triggerKey, String scheduleName, Class<?> delegateClass) {\n        super(\"No record found for selection of Trigger with key: '\" + triggerKey + \"' and Scheduler: \" + scheduleName\n        + \" and Delegate: \" + delegateClass);\n        this.triggerKey = triggerKey;\n        this.scheduleName = scheduleName;\n        this.delegateClass = delegateClass;\n        this.statement = null;\n    }\n\n    public NoRecordFoundException(TriggerKey triggerKey, String scheduleName, String statement) {\n        super(\"No record found for selection of Trigger with key: '\" + triggerKey + \"' and statement: \" + statement);\n        this.triggerKey = triggerKey;\n        this.scheduleName = scheduleName;\n        this.statement = statement;\n        this.delegateClass = null;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/NoSuchDelegateException.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.JobPersistenceException;\n\n/**\n * <p>\n * Exception class for when a driver delegate cannot be found for a given\n * configuration, or lack thereof.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class NoSuchDelegateException extends JobPersistenceException {\n\n    private static final long serialVersionUID = -4255865028975822979L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public NoSuchDelegateException(String msg) {\n        super(msg);\n    }\n\n    public NoSuchDelegateException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/PointbaseDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.math.BigDecimal;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDetail;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * <p>\n * This is a driver delegate for the Pointbase JDBC driver.\n * </p>\n * \n * @author Gregg Freeman\n */\npublic class PointbaseDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // jobs\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to insert\n     * @return number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    @Override           \n    public int insertJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        //log.debug( \"Inserting JobDetail \" + job );\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        int len = baos.toByteArray().length;\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n\n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n            ps.setString(3, job.getDescription());\n            ps.setString(4, job.getJobClass().getName());\n            setBoolean(ps, 5, job.isDurable());\n            setBoolean(ps, 6, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 7, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 8, job.requestsRecovery());\n            ps.setBinaryStream(9, bais, len);\n\n            insertResult = ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Update the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    @Override           \n    public int updateJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        //log.debug( \"Updating job detail \" + job );\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        int len = baos.toByteArray().length;\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n\n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL));\n            ps.setString(1, job.getDescription());\n            ps.setString(2, job.getJobClass().getName());\n            setBoolean(ps, 3, job.isDurable());\n            setBoolean(ps, 4, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 5, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 6, job.requestsRecovery());\n            ps.setBinaryStream(7, bais, len);\n            ps.setString(8, job.getKey().getName());\n            ps.setString(9, job.getKey().getGroup());\n\n            insertResult = ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    @Override\n    public int insertTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap());\n        int len = baos.toByteArray().length;\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        \n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_TRIGGER));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setString(3, trigger.getJobKey().getName());\n            ps.setString(4, trigger.getJobKey().getGroup());\n            ps.setString(5, trigger.getDescription());\n            ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger\n                    .getNextFireTime().getTime())));\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(7, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(8, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n            ps.setString(9, type);\n            \n            ps.setBigDecimal(10, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(11, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(12, trigger.getCalendarName());\n            ps.setInt(13, trigger.getMisfireInstruction());\n            ps.setBinaryStream(14, bais, len);\n            ps.setInt(15, trigger.getPriority());\n            \n            insertResult = ps.executeUpdate();\n            \n            if(tDel == null)\n                insertBlobTrigger(conn, trigger);\n            else\n                tDel.insertExtendedTriggerProperties(conn, trigger, state, jobDetail);\n                        \n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n    \n    @Override           \n    public int updateTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        ByteArrayOutputStream baos = serializeJobData(trigger.getJobDataMap());\n        int len = baos.toByteArray().length;\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n                \n        PreparedStatement ps = null;\n\n        int insertResult;\n\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_TRIGGER));\n                \n            ps.setString(1, trigger.getJobKey().getName());\n            ps.setString(2, trigger.getJobKey().getGroup());\n            ps.setString(3, trigger.getDescription());\n            long nextFireTime = -1;\n            if (trigger.getNextFireTime() != null) {\n                nextFireTime = trigger.getNextFireTime().getTime();\n            }\n            ps.setBigDecimal(4, new BigDecimal(String.valueOf(nextFireTime)));\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(5, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(6, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n\n            ps.setString(7, type);\n            \n            ps.setBigDecimal(8, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(9, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(10, trigger.getCalendarName());\n            ps.setInt(11, trigger.getMisfireInstruction());\n            \n            ps.setInt(12, trigger.getPriority());\n            ps.setBinaryStream(13, bais, len);\n            ps.setString(14, trigger.getKey().getName());\n            ps.setString(15, trigger.getKey().getGroup());\n\n            insertResult = ps.executeUpdate();\n            \n            if(tDel == null)\n                updateBlobTrigger(conn, trigger);\n            else\n                tDel.updateExtendedTriggerProperties(conn, trigger, state, jobDetail);\n            \n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Update the job data map for the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return the number of rows updated\n     */\n    @Override           \n    public int updateJobData(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        //log.debug( \"Updating Job Data for Job \" + job );\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        int len = baos.toByteArray().length;\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA));\n            ps.setBinaryStream(1, bais, len);\n            ps.setString(2, job.getKey().getName());\n            ps.setString(3, job.getKey().getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    //---------------------------------------------------------------------------\n    // triggers\n    //---------------------------------------------------------------------------\n\n    //---------------------------------------------------------------------------\n    // calendars\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert a new calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    @Override           \n    public int insertCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        //log.debug( \"Inserting Calendar \" + calendarName + \" : \" + calendar\n        // );\n        ByteArrayOutputStream baos = serializeObject(calendar);\n        byte buf[] = baos.toByteArray();\n        ByteArrayInputStream bais = new ByteArrayInputStream(buf);\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_CALENDAR));\n            ps.setString(1, calendarName);\n            ps.setBinaryStream(2, bais, buf.length);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    @Override           \n    public int updateCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        //log.debug( \"Updating calendar \" + calendarName + \" : \" + calendar );\n        ByteArrayOutputStream baos = serializeObject(calendar);\n        byte buf[] = baos.toByteArray();\n        ByteArrayInputStream bais = new ByteArrayInputStream(buf);\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_CALENDAR));\n            ps.setBinaryStream(1, bais, buf.length);\n            ps.setString(2, calendarName);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        //log.debug( \"Getting blob from column: \" + colName );\n        Object obj = null;\n\n        byte binaryData[] = rs.getBytes(colName);\n\n        InputStream binaryInput = new ByteArrayInputStream(binaryData);\n\n        if (binaryInput.available() != 0) {\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n        }\n\n        return obj;\n    }\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs for job details. The default implementation\n     * uses standard JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        //log.debug( \"Getting Job details from blob in col \" + colName );\n        if (canUseProperties()) {\n            byte data[] = rs.getBytes(colName);\n            if(data == null) {\n                return null;\n            }\n            return new ByteArrayInputStream(data);\n        }\n\n        return getObjectFromBlob(rs, colName);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/PostgreSQLDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for the PostgreSQL JDBC driver.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class PostgreSQLDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        InputStream binaryInput;\n        byte[] bytes = rs.getBytes(colName);\n        \n        Object obj = null;\n        \n        if(bytes != null && bytes.length != 0) {\n            binaryInput = new ByteArrayInputStream(bytes);\n\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n\n        }\n        \n        return obj;\n    }\n\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            InputStream binaryInput;\n            byte[] bytes = rs.getBytes(colName);\n            if(bytes == null || bytes.length == 0) {\n                return null;\n            }\n            binaryInput = new ByteArrayInputStream(bytes);\n            return binaryInput;\n        }\n        return getObjectFromBlob(rs, colName);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SchedulerStateRecord.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\n/**\n * <p>\n * Conveys a scheduler-instance state record.\n * </p>\n * \n * @author James House\n */\npublic class SchedulerStateRecord implements java.io.Serializable {\n\n    private static final long serialVersionUID = -715704959016191445L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private String schedulerInstanceId;\n\n    private long checkinTimestamp;\n\n    private long checkinInterval;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     */\n    public long getCheckinInterval() {\n        return checkinInterval;\n    }\n\n    /**\n     */\n    public long getCheckinTimestamp() {\n        return checkinTimestamp;\n    }\n\n    /**\n     */\n    public String getSchedulerInstanceId() {\n        return schedulerInstanceId;\n    }\n\n    /**\n     */\n    public void setCheckinInterval(long l) {\n        checkinInterval = l;\n    }\n\n    /**\n     */\n    public void setCheckinTimestamp(long l) {\n        checkinTimestamp = l;\n    }\n\n    /**\n     */\n    public void setSchedulerInstanceId(String string) {\n        schedulerInstanceId = string;\n    }\n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/Semaphore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\n\n/**\n * An interface for providing thread/resource locking in order to protect\n * resources from being altered by multiple threads at the same time.\n * \n * @author jhouse\n */\npublic interface Semaphore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Grants a lock on the identified resource to the calling thread (blocking\n     * until it is available).\n     * \n     * @param conn Database connection used to establish lock.  Can be null if\n     * <code>{@link #requiresConnection()}</code> returns false.\n     * \n     * @return true if the lock was obtained.\n     */\n    boolean obtainLock(Connection conn, String lockName) throws LockException;\n\n    /**\n     * Release the lock on the identified resource if it is held by the calling\n     * thread.\n     */\n    void releaseLock(String lockName) throws LockException;\n\n    /**\n     * Whether this Semaphore implementation requires a database connection for\n     * its lock management operations.\n     * \n     * @see #obtainLock(Connection, String)\n     * @see #releaseLock(String)\n     */\n    boolean requiresConnection();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SimplePropertiesTriggerPersistenceDelegateSupport.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.JobDetail;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * A base implementation of {@link TriggerPersistenceDelegate} that persists \n * trigger fields in the \"QRTZ_SIMPROP_TRIGGERS\" table.  This allows extending\n * concrete classes to simply implement a couple methods that do the work of\n * getting/setting the trigger's fields, and creating the {@link ScheduleBuilder}\n * for the particular type of trigger. \n * \n * @see CalendarIntervalTriggerPersistenceDelegate for an example extension\n * \n * @author jhouse\n */\npublic abstract class SimplePropertiesTriggerPersistenceDelegateSupport implements TriggerPersistenceDelegate, StdJDBCConstants {\n\n    protected static final String TABLE_SIMPLE_PROPERTIES_TRIGGERS = \"SIMPROP_TRIGGERS\";\n    \n    protected static final String COL_STR_PROP_1 = \"STR_PROP_1\";\n    protected static final String COL_STR_PROP_2 = \"STR_PROP_2\";\n    protected static final String COL_STR_PROP_3 = \"STR_PROP_3\";\n    protected static final String COL_INT_PROP_1 = \"INT_PROP_1\";\n    protected static final String COL_INT_PROP_2 = \"INT_PROP_2\";\n    protected static final String COL_LONG_PROP_1 = \"LONG_PROP_1\";\n    protected static final String COL_LONG_PROP_2 = \"LONG_PROP_2\";\n    protected static final String COL_DEC_PROP_1 = \"DEC_PROP_1\";\n    protected static final String COL_DEC_PROP_2 = \"DEC_PROP_2\";\n    protected static final String COL_BOOL_PROP_1 = \"BOOL_PROP_1\";\n    protected static final String COL_BOOL_PROP_2 = \"BOOL_PROP_2\";\n    \n    protected static final String SELECT_SIMPLE_PROPS_TRIGGER = \"SELECT *\" + \" FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_SIMPLE_PROPERTIES_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    protected static final String DELETE_SIMPLE_PROPS_TRIGGER = \"DELETE FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_SIMPLE_PROPERTIES_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    protected static final String INSERT_SIMPLE_PROPS_TRIGGER = \"INSERT INTO \"\n        + TABLE_PREFIX_SUBST + TABLE_SIMPLE_PROPERTIES_TRIGGERS + \" (\"\n        + COL_SCHEDULER_NAME + \", \"\n        + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \"\n        + COL_STR_PROP_1 + \", \" + COL_STR_PROP_2 + \", \" + COL_STR_PROP_3 + \", \"\n        + COL_INT_PROP_1 + \", \" + COL_INT_PROP_2 + \", \"\n        + COL_LONG_PROP_1 + \", \" + COL_LONG_PROP_2 + \", \"\n        + COL_DEC_PROP_1 + \", \" + COL_DEC_PROP_2 + \", \"\n        + COL_BOOL_PROP_1 + \", \" + COL_BOOL_PROP_2 \n        + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\";\n\n    protected static final String UPDATE_SIMPLE_PROPS_TRIGGER = \"UPDATE \"\n        + TABLE_PREFIX_SUBST + TABLE_SIMPLE_PROPERTIES_TRIGGERS + \" SET \"\n        + COL_STR_PROP_1 + \" = ?, \" + COL_STR_PROP_2 + \" = ?, \" + COL_STR_PROP_3 + \" = ?, \"\n        + COL_INT_PROP_1 + \" = ?, \" + COL_INT_PROP_2 + \" = ?, \"\n        + COL_LONG_PROP_1 + \" = ?, \" + COL_LONG_PROP_2 + \" = ?, \"\n        + COL_DEC_PROP_1 + \" = ?, \" + COL_DEC_PROP_2 + \" = ?, \"\n        + COL_BOOL_PROP_1 + \" = ?, \" + COL_BOOL_PROP_2 \n        + \" = ? WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME\n        + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n    \n    protected String tablePrefix;\n\n    protected String schedNameLiteral;\n\n    public void initialize(String theTablePrefix, String schedName) {\n        this.tablePrefix = theTablePrefix;\n        this.schedNameLiteral = \"'\" + schedName + \"'\";\n    }\n\n    protected abstract SimplePropertiesTriggerProperties getTriggerProperties(OperableTrigger trigger);\n    \n    protected abstract TriggerPropertyBundle getTriggerPropertyBundle(SimplePropertiesTriggerProperties properties);\n    \n    public int deleteExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(DELETE_SIMPLE_PROPS_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public int insertExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        SimplePropertiesTriggerProperties properties = getTriggerProperties(trigger);\n        \n        PreparedStatement ps = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(INSERT_SIMPLE_PROPS_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setString(3, properties.getString1());\n            ps.setString(4, properties.getString2());\n            ps.setString(5, properties.getString3());\n            ps.setInt(6, properties.getInt1());\n            ps.setInt(7, properties.getInt2());\n            ps.setLong(8, properties.getLong1());\n            ps.setLong(9, properties.getLong2());\n            ps.setBigDecimal(10, properties.getDecimal1());\n            ps.setBigDecimal(11, properties.getDecimal2());\n            ps.setBoolean(12, properties.isBoolean1());\n            ps.setBoolean(13, properties.isBoolean2());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public TriggerPropertyBundle loadExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(SELECT_SIMPLE_PROPS_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n    \n            if (rs.next()) {\n                return loadExtendedTriggerPropertiesFromResultSet(rs, triggerKey);\n            }\n\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, Util.rtp(SELECT_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n        } finally {\n            Util.closeResultSet(rs);\n            Util.closeStatement(ps);\n        }\n    }\n\n    public TriggerPropertyBundle loadExtendedTriggerPropertiesFromResultSet(ResultSet rs, TriggerKey triggerKey) throws SQLException {\n        SimplePropertiesTriggerProperties properties = new SimplePropertiesTriggerProperties();\n        if (Util.areNull(rs, COL_STR_PROP_1, COL_STR_PROP_2, COL_STR_PROP_3,\n                COL_INT_PROP_1, COL_INT_PROP_2,\n                COL_LONG_PROP_1, COL_LONG_PROP_2,\n                COL_DEC_PROP_1, COL_DEC_PROP_2,\n                COL_BOOL_PROP_1, COL_BOOL_PROP_2)) {\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, this.getClass());\n        }\n\n        properties.setString1(rs.getString(COL_STR_PROP_1));\n        properties.setString2(rs.getString(COL_STR_PROP_2));\n        properties.setString3(rs.getString(COL_STR_PROP_3));\n        properties.setInt1(rs.getInt(COL_INT_PROP_1));\n        properties.setInt2(rs.getInt(COL_INT_PROP_2));\n        properties.setLong1(rs.getLong(COL_LONG_PROP_1));\n        properties.setLong2(rs.getLong(COL_LONG_PROP_2));\n        properties.setDecimal1(rs.getBigDecimal(COL_DEC_PROP_1));\n        properties.setDecimal2(rs.getBigDecimal(COL_DEC_PROP_2));\n        properties.setBoolean1(rs.getBoolean(COL_BOOL_PROP_1));\n        properties.setBoolean2(rs.getBoolean(COL_BOOL_PROP_2));\n\n        return getTriggerPropertyBundle(properties);\n    }\n\n    public boolean hasInlinedResultSetProperties() {\n        return true;\n    }\n\n    public int updateExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        SimplePropertiesTriggerProperties properties = getTriggerProperties(trigger);\n        \n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(UPDATE_SIMPLE_PROPS_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, properties.getString1());\n            ps.setString(2, properties.getString2());\n            ps.setString(3, properties.getString3());\n            ps.setInt(4, properties.getInt1());\n            ps.setInt(5, properties.getInt2());\n            ps.setLong(6, properties.getLong1());\n            ps.setLong(7, properties.getLong2());\n            ps.setBigDecimal(8, properties.getDecimal1());\n            ps.setBigDecimal(9, properties.getDecimal2());\n            ps.setBoolean(10, properties.isBoolean1());\n            ps.setBoolean(11, properties.isBoolean2());\n            ps.setString(12, trigger.getKey().getName());\n            ps.setString(13, trigger.getKey().getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SimplePropertiesTriggerProperties.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.math.BigDecimal;\n\npublic class SimplePropertiesTriggerProperties {\n\n    private String string1;\n    private String string2;\n    private String string3;\n    \n    private int int1;\n    private int int2;\n\n    private long long1;\n    private long long2;\n    \n    private BigDecimal decimal1;\n    private BigDecimal decimal2;\n    \n    private boolean boolean1;\n    private boolean boolean2;\n    \n    \n    public String getString1() {\n        return string1;\n    }\n    public void setString1(String string1) {\n        this.string1 = string1;\n    }\n    public String getString2() {\n        return string2;\n    }\n    public void setString2(String string2) {\n        this.string2 = string2;\n    }\n    public String getString3() {\n        return string3;\n    }\n    public void setString3(String string3) {\n        this.string3 = string3;\n    }\n    public int getInt1() {\n        return int1;\n    }\n    public void setInt1(int int1) {\n        this.int1 = int1;\n    }\n    public int getInt2() {\n        return int2;\n    }\n    public void setInt2(int int2) {\n        this.int2 = int2;\n    }\n    public long getLong1() {\n        return long1;\n    }\n    public void setLong1(long long1) {\n        this.long1 = long1;\n    }\n    public long getLong2() {\n        return long2;\n    }\n    public void setLong2(long long2) {\n        this.long2 = long2;\n    }\n    public BigDecimal getDecimal1() {\n        return decimal1;\n    }\n    public void setDecimal1(BigDecimal decimal1) {\n        this.decimal1 = decimal1;\n    }\n    public BigDecimal getDecimal2() {\n        return decimal2;\n    }\n    public void setDecimal2(BigDecimal decimal2) {\n        this.decimal2 = decimal2;\n    }\n    public boolean isBoolean1() {\n        return boolean1;\n    }\n    public void setBoolean1(boolean boolean1) {\n        this.boolean1 = boolean1;\n    }\n    public boolean isBoolean2() {\n        return boolean2;\n    }\n    public void setBoolean2(boolean boolean2) {\n        this.boolean2 = boolean2;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SimpleSemaphore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.util.HashSet;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Internal in-memory lock handler for providing thread/resource locking in \n * order to protect resources from being altered by multiple threads at the \n * same time.\n * \n * @author jhouse\n */\npublic class SimpleSemaphore implements Semaphore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    final ThreadLocal<HashSet<String>> lockOwners = new ThreadLocal<>();\n\n    final HashSet<String> locks = new HashSet<>();\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    private HashSet<String> getThreadLocks() {\n        HashSet<String> threadLocks = lockOwners.get();\n        if (threadLocks == null) {\n            threadLocks = new HashSet<>();\n            lockOwners.set(threadLocks);\n        }\n        return threadLocks;\n    }\n\n    /**\n     * Grants a lock on the identified resource to the calling thread (blocking\n     * until it is available).\n     * \n     * @return true if the lock was obtained.\n     */\n    public synchronized boolean obtainLock(Connection conn, String lockName) {\n\n        lockName = lockName.intern();\n\n        if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' is desired by: {}\", lockName, Thread.currentThread().getName());\n        }\n\n        if (!isLockOwner(lockName)) {\n            if(log.isDebugEnabled()) {\n                log.debug(\"Lock '{}' is being obtained: {}\", lockName, Thread.currentThread().getName());\n            }\n            while (locks.contains(lockName)) {\n                try {\n                    this.wait();\n                } catch (InterruptedException ie) {\n                    if(log.isDebugEnabled()) {\n                        log.debug(\"Lock '{}' was not obtained by: {}\", lockName, Thread.currentThread().getName());\n                    }\n                }\n            }\n\n            if(log.isDebugEnabled()) {\n                log.debug(\"Lock '{}' given to: {}\", lockName, Thread.currentThread().getName());\n            }\n            getThreadLocks().add(lockName);\n            locks.add(lockName);\n        } else if(log.isDebugEnabled()) {\n            log.debug(\"Lock '{}' already owned by: {} -- but not owner!\", lockName, Thread.currentThread().getName(), new Exception(\"stack-trace of wrongful returner\"));\n        }\n\n        return true;\n    }\n\n    /**\n     * Release the lock on the identified resource if it is held by the calling\n     * thread.\n     */\n    public synchronized void releaseLock(String lockName) {\n\n        lockName = lockName.intern();\n\n        if (isLockOwner(lockName)) {\n            if(getLog().isDebugEnabled()) {\n                getLog().debug(\"Lock '{}' returned by: {}\", lockName, Thread.currentThread().getName());\n            }\n            getThreadLocks().remove(lockName);\n            locks.remove(lockName);\n            this.notifyAll();\n        } else if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Lock '{}' attempt to return by: {} -- but not owner!\", lockName, Thread.currentThread().getName(), new Exception(\"stack-trace of wrongful returner\"));\n        }\n    }\n\n    /**\n     * Determine whether the calling thread owns a lock on the identified\n     * resource.\n     */\n    public synchronized boolean isLockOwner(String lockName) {\n\n        lockName = lockName.intern();\n\n        return getThreadLocks().contains(lockName);\n    }\n\n    /**\n     * This Semaphore implementation does not use the database.\n     */\n    public boolean requiresConnection() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SimpleTriggerPersistenceDelegate.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.JobDetail;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.OperableTrigger;\n\npublic class SimpleTriggerPersistenceDelegate implements TriggerPersistenceDelegate, StdJDBCConstants {\n\n    protected String tablePrefix;\n    protected String schedNameLiteral;\n\n    public void initialize(String theTablePrefix, String schedName) {\n        this.tablePrefix = theTablePrefix;\n        this.schedNameLiteral = \"'\" + schedName + \"'\";\n    }\n\n    public String getHandledTriggerTypeDiscriminator() {\n        return TTYPE_SIMPLE;\n    }\n\n    public boolean canHandleTriggerType(OperableTrigger trigger) {\n        return ((trigger instanceof SimpleTriggerImpl) && !((SimpleTriggerImpl)trigger).hasAdditionalProperties());\n    }\n\n    public int deleteExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(DELETE_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public int insertExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        SimpleTrigger simpleTrigger = (SimpleTrigger)trigger;\n        \n        PreparedStatement ps = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(INSERT_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setInt(3, simpleTrigger.getRepeatCount());\n            ps.setBigDecimal(4, new BigDecimal(String.valueOf(simpleTrigger.getRepeatInterval())));\n            ps.setInt(5, simpleTrigger.getTimesTriggered());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n    public TriggerPropertyBundle loadExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException {\n\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        \n        try {\n            ps = conn.prepareStatement(Util.rtp(SELECT_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n    \n            if (rs.next()) {\n                return loadExtendedTriggerPropertiesFromResultSet(rs, triggerKey);\n            }\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, Util.rtp(SELECT_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n        } finally {\n            Util.closeResultSet(rs);\n            Util.closeStatement(ps);\n        }\n    }\n\n    public TriggerPropertyBundle loadExtendedTriggerPropertiesFromResultSet(ResultSet rs, TriggerKey triggerKey) throws SQLException {\n        if (Util.areNull(rs, COL_REPEAT_COUNT, COL_REPEAT_INTERVAL, COL_TIMES_TRIGGERED)) {\n            throw new NoRecordFoundException(triggerKey, schedNameLiteral, this.getClass());\n        }\n        int repeatCount = rs.getInt(COL_REPEAT_COUNT);\n        long repeatInterval = rs.getLong(COL_REPEAT_INTERVAL);\n        int timesTriggered = rs.getInt(COL_TIMES_TRIGGERED);\n\n        SimpleScheduleBuilder sb = SimpleScheduleBuilder.simpleSchedule()\n            .withRepeatCount(repeatCount)\n            .withIntervalInMilliseconds(repeatInterval);\n\n        String[] statePropertyNames = { \"timesTriggered\" };\n        Object[] statePropertyValues = { timesTriggered };\n\n        return new TriggerPropertyBundle(sb, statePropertyNames, statePropertyValues);\n    }\n\n    public boolean hasInlinedResultSetProperties() {\n        return true;\n    }\n\n    public int updateExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException {\n\n        SimpleTrigger simpleTrigger = (SimpleTrigger)trigger;\n        \n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(Util.rtp(UPDATE_SIMPLE_TRIGGER, tablePrefix, schedNameLiteral));\n\n            ps.setInt(1, simpleTrigger.getRepeatCount());\n            ps.setBigDecimal(2, new BigDecimal(String.valueOf(simpleTrigger.getRepeatInterval())));\n            ps.setInt(3, simpleTrigger.getTimesTriggered());\n            ps.setString(4, simpleTrigger.getKey().getName());\n            ps.setString(5, simpleTrigger.getKey().getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            Util.closeStatement(ps);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/StdJDBCConstants.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_BOOL_PROP_1;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_BOOL_PROP_2;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_DEC_PROP_1;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_DEC_PROP_2;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_INT_PROP_1;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_INT_PROP_2;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_LONG_PROP_1;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_LONG_PROP_2;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_STR_PROP_1;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_STR_PROP_2;\nimport static org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport.COL_STR_PROP_3;\n\nimport org.quartz.Trigger;\n\n/**\n * <p>\n * This interface extends <code>{@link\n * org.quartz.impl.jdbcjobstore.Constants}</code>\n * to include the query string constants in use by the <code>{@link\n * org.quartz.impl.jdbcjobstore.StdJDBCDelegate}</code>\n * class.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic interface StdJDBCConstants extends Constants {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    // table prefix substitution string\n    String TABLE_PREFIX_SUBST = \"{0}\";\n\n    // table prefix substitution string\n    String SCHED_NAME_SUBST = \"{1}\";\n\n    // QUERIES\n    String UPDATE_TRIGGER_STATES_FROM_OTHER_STATES = \"UPDATE \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS\n            + \" SET \"\n            + COL_TRIGGER_STATE\n            + \" = ?\"\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME \n            + \" = \" + SCHED_NAME_SUBST + \" AND (\"\n            + COL_TRIGGER_STATE\n            + \" = ? OR \"\n            + COL_TRIGGER_STATE + \" = ?)\";\n\n    String SELECT_MISFIRED_TRIGGERS = \"SELECT * FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND NOT (\"\n        + COL_MISFIRE_INSTRUCTION + \" = \" + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + \") AND \" \n        + COL_NEXT_FIRE_TIME + \" < ? \"\n        + \"ORDER BY \" + COL_NEXT_FIRE_TIME + \" ASC, \" + COL_PRIORITY + \" DESC\";\n    \n    String SELECT_TRIGGERS_IN_STATE = \"SELECT \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND \"\n            + COL_TRIGGER_STATE + \" = ?\";\n\n    String SELECT_MISFIRED_TRIGGERS_IN_STATE = \"SELECT \"\n        + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND NOT (\"\n        + COL_MISFIRE_INSTRUCTION + \" = \" + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + \") AND \" \n        + COL_NEXT_FIRE_TIME + \" < ? AND \" + COL_TRIGGER_STATE + \" = ? \"\n        + \"ORDER BY \" + COL_NEXT_FIRE_TIME + \" ASC, \" + COL_PRIORITY + \" DESC\";\n\n    String COUNT_MISFIRED_TRIGGERS_IN_STATE = \"SELECT COUNT(\"\n        + COL_TRIGGER_NAME + \") FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND NOT (\"\n        + COL_MISFIRE_INSTRUCTION + \" = \" + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + \") AND \" \n        + COL_NEXT_FIRE_TIME + \" < ? \" \n        + \"AND \" + COL_TRIGGER_STATE + \" = ?\";\n    \n    String SELECT_HAS_MISFIRED_TRIGGERS_IN_STATE = \"SELECT \"\n        + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND NOT (\"\n        + COL_MISFIRE_INSTRUCTION + \" = \" + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + \") AND \" \n        + COL_NEXT_FIRE_TIME + \" < ? \" \n        + \"AND \" + COL_TRIGGER_STATE + \" = ? \"\n        + \"ORDER BY \" + COL_NEXT_FIRE_TIME + \" ASC, \" + COL_PRIORITY + \" DESC\";\n\n    String SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE = \"SELECT \"\n        + COL_TRIGGER_NAME\n        + \" FROM \"\n        + TABLE_PREFIX_SUBST\n        + TABLE_TRIGGERS\n        + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND NOT (\"\n        + COL_MISFIRE_INSTRUCTION + \" = \" + Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY + \") AND \" \n        + COL_NEXT_FIRE_TIME\n        + \" < ? AND \"\n        + COL_TRIGGER_GROUP\n        + \" = ? AND \" + COL_TRIGGER_STATE + \" = ? \"\n        + \"ORDER BY \" + COL_NEXT_FIRE_TIME + \" ASC, \" + COL_PRIORITY + \" DESC\";\n\n\n    String DELETE_FIRED_TRIGGERS = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String INSERT_JOB_DETAIL = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" (\" \n            + COL_SCHEDULER_NAME + \", \" + COL_JOB_NAME\n            + \", \" + COL_JOB_GROUP + \", \" + COL_DESCRIPTION + \", \"\n            + COL_JOB_CLASS + \", \" + COL_IS_DURABLE + \", \" \n            + COL_IS_NONCONCURRENT +  \", \" + COL_IS_UPDATE_DATA + \", \" \n            + COL_REQUESTS_RECOVERY + \", \"\n            + COL_JOB_DATAMAP + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?, ?, ?, ?, ?)\";\n\n    String UPDATE_JOB_DETAIL = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" SET \"\n            + COL_DESCRIPTION + \" = ?, \" + COL_JOB_CLASS + \" = ?, \"\n            + COL_IS_DURABLE + \" = ?, \" \n            + COL_IS_NONCONCURRENT + \" = ?, \" + COL_IS_UPDATE_DATA + \" = ?, \" \n            + COL_REQUESTS_RECOVERY + \" = ?, \"\n            + COL_JOB_DATAMAP + \" = ? \" + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_TRIGGERS_FOR_JOB = \"SELECT \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_TRIGGERS_FOR_CALENDAR = \"SELECT \"\n        + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \" \n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n        + \" AND \" + COL_CALENDAR_NAME\n        + \" = ?\";\n\n    String SELECT_BULK_TRIGGERS_BASE = \"SELECT \"\n        + \"T.\" + COL_SCHEDULER_NAME + \", T.\" + COL_TRIGGER_NAME + \", T.\" + COL_TRIGGER_GROUP + \", T.\" + COL_JOB_NAME + \", T.\" + COL_JOB_GROUP + \", T.\" + COL_DESCRIPTION + \", T.\" + COL_NEXT_FIRE_TIME + \", \"\n        + \"T.\" + COL_PREV_FIRE_TIME + \", T.\" + COL_PRIORITY + \", T.\" + COL_TRIGGER_STATE + \", T.\" + COL_TRIGGER_TYPE + \", T.\" + COL_START_TIME + \", T.\" + COL_END_TIME + \", T.\" + COL_CALENDAR_NAME + \", T.\" + COL_MISFIRE_INSTRUCTION + \", T.\" + COL_JOB_DATAMAP + \", \"\n        + \"QBT.\" + COL_BLOB + \", \"\n        + \"QCT.\" + COL_CRON_EXPRESSION + \", QCT.\" + COL_TIME_ZONE_ID + \", \"\n        + \"QST.\" + COL_REPEAT_COUNT + \", QST.\" + COL_REPEAT_INTERVAL + \", QST.\" + COL_TIMES_TRIGGERED + \", \"\n        + \"QSP.\" + COL_STR_PROP_1 + \", QSP.\" + COL_STR_PROP_2 + \", QSP.\" + COL_STR_PROP_3 + \", QSP.\" + COL_INT_PROP_1 + \", \"\n        + \"QSP.\" + COL_INT_PROP_2 + \", QSP.\" + COL_LONG_PROP_1 + \", QSP.\" + COL_LONG_PROP_2 + \", QSP.\" + COL_DEC_PROP_1 + \", \"\n        + \"QSP.\" + COL_DEC_PROP_2 + \", QSP.\" + COL_BOOL_PROP_1 + \", QSP.\" + COL_BOOL_PROP_2 + \" \"\n        + \"FROM \" + TABLE_PREFIX_SUBST + \"TRIGGERS T \"\n        + \"LEFT JOIN \" + TABLE_PREFIX_SUBST + \"BLOB_TRIGGERS QBT ON \"\n        + \"T.\" + COL_SCHEDULER_NAME + \" = QBT.\" + COL_SCHEDULER_NAME + \" AND T.\" + COL_TRIGGER_NAME + \" = QBT.\" + COL_TRIGGER_NAME + \" AND T.\" + COL_TRIGGER_GROUP + \" = QBT.\" + COL_TRIGGER_GROUP + \" \"\n        + \"LEFT JOIN \" + TABLE_PREFIX_SUBST + \"CRON_TRIGGERS QCT ON \"\n        + \"T.\" + COL_SCHEDULER_NAME + \" = QCT.\" + COL_SCHEDULER_NAME + \" AND T.\" + COL_TRIGGER_NAME + \" = QCT.\" + COL_TRIGGER_NAME + \" AND T.\" + COL_TRIGGER_GROUP + \" = QCT.\" + COL_TRIGGER_GROUP + \" \"\n        + \"LEFT JOIN \" + TABLE_PREFIX_SUBST + \"SIMPLE_TRIGGERS QST ON \"\n        + \"T.\" + COL_SCHEDULER_NAME + \" = QST.\" + COL_SCHEDULER_NAME + \" AND T.\" + COL_TRIGGER_NAME + \" = QST.\" + COL_TRIGGER_NAME + \" AND T.\" + COL_TRIGGER_GROUP + \" = QST.\" + COL_TRIGGER_GROUP + \" \"\n        + \"LEFT JOIN \" + TABLE_PREFIX_SUBST + \"SIMPROP_TRIGGERS QSP ON \"\n        + \"T.\" + COL_SCHEDULER_NAME + \" = QSP.\" + COL_SCHEDULER_NAME + \" AND T.\" + COL_TRIGGER_NAME + \" = QSP.\" + COL_TRIGGER_NAME + \" AND T.\" + COL_TRIGGER_GROUP + \" = QSP.\" + COL_TRIGGER_GROUP + \" \";\n\n    String SELECT_TRIGGERS_FOR_CALENDAR_V2 = SELECT_BULK_TRIGGERS_BASE\n        + \"WHERE T.\" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String SELECT_TRIGGERS_FOR_JOB_V2 = SELECT_BULK_TRIGGERS_BASE\n        + \"WHERE T.\" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_JOB_NAME + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_TRIGGERS_WITH_MATCHERS = SELECT_BULK_TRIGGERS_BASE\n        + \"WHERE T.\" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND T.\" + COL_TRIGGER_GROUP + \" {JOB_GROUP_LIKE} ?\"\n        + \" AND T.\" + COL_TRIGGER_NAME + \" {TRIGGER_NAME_LIKE} ?\";\n\n    String DELETE_JOB_DETAIL = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_JOB_NONCONCURRENT = \"SELECT \"\n            + COL_IS_NONCONCURRENT + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_JOB_DETAILS + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_JOB_EXISTENCE = \"SELECT \" + COL_JOB_NAME\n            + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String UPDATE_JOB_DATA = \"UPDATE \" + TABLE_PREFIX_SUBST\n            + TABLE_JOB_DETAILS + \" SET \" + COL_JOB_DATAMAP + \" = ? \"\n            + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_JOB_DETAIL = \"SELECT *\" + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_JOB_DETAILS_LIKE = \"SELECT *\" + \" FROM \" +\n        TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_JOB_GROUP + \" LIKE ?\";\n\n    String SELECT_JOB_DETAILS = \"SELECT *\" + \" FROM \" +\n        TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_JOB_GROUP + \" LIKE ?\";\n\n    String SELECT_NUM_JOBS = \"SELECT COUNT(\" + COL_JOB_NAME\n            + \") \" + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_JOB_GROUPS = \"SELECT DISTINCT(\"\n            + COL_JOB_GROUP + \") FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_JOBS_IN_GROUP_LIKE = \"SELECT \" + COL_JOB_NAME + \", \" + COL_JOB_GROUP\n            + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_GROUP + \" LIKE ?\";\n\n    String SELECT_JOBS_IN_GROUP = \"SELECT \" + COL_JOB_NAME + \", \" + COL_JOB_GROUP\n            + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String INSERT_TRIGGER = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" (\" + COL_SCHEDULER_NAME + \", \" + COL_TRIGGER_NAME\n            + \", \" + COL_TRIGGER_GROUP + \", \" + COL_JOB_NAME + \", \"\n            + COL_JOB_GROUP + \", \" + COL_DESCRIPTION\n            + \", \" + COL_NEXT_FIRE_TIME + \", \" + COL_PREV_FIRE_TIME + \", \"\n            + COL_TRIGGER_STATE + \", \" + COL_TRIGGER_TYPE + \", \"\n            + COL_START_TIME + \", \" + COL_END_TIME + \", \" + COL_CALENDAR_NAME\n            + \", \" + COL_MISFIRE_INSTRUCTION + \", \" + COL_JOB_DATAMAP + \", \" + COL_PRIORITY + \") \"\n            + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\";\n\n    String INSERT_SIMPLE_TRIGGER = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + \" (\"\n            + COL_SCHEDULER_NAME + \", \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \"\n            + COL_REPEAT_COUNT + \", \" + COL_REPEAT_INTERVAL + \", \"\n            + COL_TIMES_TRIGGERED + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?)\";\n\n    String INSERT_CRON_TRIGGER = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + \" (\"\n            + COL_SCHEDULER_NAME + \", \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \"\n            + COL_CRON_EXPRESSION + \", \" + COL_TIME_ZONE_ID + \") \"\n            + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?)\";\n\n    String INSERT_BLOB_TRIGGER = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + \" (\"\n            + COL_SCHEDULER_NAME + \", \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \" + COL_BLOB\n            + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?)\";\n\n    String UPDATE_TRIGGER_SKIP_DATA = \"UPDATE \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" SET \" + COL_JOB_NAME + \" = ?, \"\n            + COL_JOB_GROUP + \" = ?, \" \n            + COL_DESCRIPTION + \" = ?, \" + COL_NEXT_FIRE_TIME + \" = ?, \"\n            + COL_PREV_FIRE_TIME + \" = ?, \" + COL_TRIGGER_STATE + \" = ?, \"\n            + COL_TRIGGER_TYPE + \" = ?, \" + COL_START_TIME + \" = ?, \"\n            + COL_END_TIME + \" = ?, \" + COL_CALENDAR_NAME + \" = ?, \"\n            + COL_MISFIRE_INSTRUCTION + \" = ?, \" + COL_PRIORITY \n            + \" = ? WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME\n            + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String UPDATE_TRIGGER = \"UPDATE \" + TABLE_PREFIX_SUBST\n        + TABLE_TRIGGERS + \" SET \" + COL_JOB_NAME + \" = ?, \"\n        + COL_JOB_GROUP + \" = ?, \"\n        + COL_DESCRIPTION + \" = ?, \" + COL_NEXT_FIRE_TIME + \" = ?, \"\n        + COL_PREV_FIRE_TIME + \" = ?, \" + COL_TRIGGER_STATE + \" = ?, \"\n        + COL_TRIGGER_TYPE + \" = ?, \" + COL_START_TIME + \" = ?, \"\n        + COL_END_TIME + \" = ?, \" + COL_CALENDAR_NAME + \" = ?, \"\n        + COL_MISFIRE_INSTRUCTION + \" = ?, \" + COL_PRIORITY + \" = ?, \" \n        + COL_JOB_DATAMAP + \" = ? WHERE \" \n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n    \n    String UPDATE_SIMPLE_TRIGGER = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + \" SET \"\n            + COL_REPEAT_COUNT + \" = ?, \" + COL_REPEAT_INTERVAL + \" = ?, \"\n            + COL_TIMES_TRIGGERED + \" = ? WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME\n            + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String UPDATE_CRON_TRIGGER = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + \" SET \"\n            + COL_CRON_EXPRESSION + \" = ?, \" + COL_TIME_ZONE_ID  \n            + \" = ? WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME\n            + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String UPDATE_BLOB_TRIGGER = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + \" SET \" + COL_BLOB\n            + \" = ? WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n            + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_TRIGGER_EXISTENCE = \"SELECT \"\n            + COL_TRIGGER_NAME + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP\n            + \" = ?\";\n\n    String UPDATE_TRIGGER_STATE = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \" + COL_TRIGGER_STATE\n            + \" = ?\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n            + COL_TRIGGER_GROUP + \" = ?\";\n\n    String UPDATE_TRIGGER_STATE_FROM_STATE = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \" + COL_TRIGGER_STATE\n            + \" = ?\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n            + COL_TRIGGER_GROUP + \" = ? AND \" + COL_TRIGGER_STATE + \" = ?\";\n\n    String UPDATE_TRIGGER_GROUP_STATE_FROM_STATE = \"UPDATE \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS\n            + \" SET \"\n            + COL_TRIGGER_STATE\n            + \" = ?\"\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP\n            + \" LIKE ? AND \"\n            + COL_TRIGGER_STATE + \" = ?\";\n\n    String UPDATE_TRIGGER_STATE_FROM_STATES = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \" + COL_TRIGGER_STATE\n            + \" = ?\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n            + COL_TRIGGER_GROUP + \" = ? AND (\" + COL_TRIGGER_STATE + \" = ? OR \"\n            + COL_TRIGGER_STATE + \" = ? OR \" + COL_TRIGGER_STATE + \" = ?)\";\n\n    String UPDATE_TRIGGER_GROUP_STATE_FROM_STATES = \"UPDATE \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS\n            + \" SET \"\n            + COL_TRIGGER_STATE\n            + \" = ?\"\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP\n            + \" LIKE ? AND (\"\n            + COL_TRIGGER_STATE\n            + \" = ? OR \"\n            + COL_TRIGGER_STATE\n            + \" = ? OR \"\n            + COL_TRIGGER_STATE + \" = ?)\";\n\n    String UPDATE_JOB_TRIGGER_STATES = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \" + COL_TRIGGER_STATE\n            + \" = ? WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \" + COL_JOB_GROUP\n            + \" = ?\";\n\n    String UPDATE_JOB_TRIGGER_STATES_FROM_OTHER_STATE = \"UPDATE \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS\n            + \" SET \"\n            + COL_TRIGGER_STATE\n            + \" = ? WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \"\n            + COL_JOB_GROUP\n            + \" = ? AND \" + COL_TRIGGER_STATE + \" = ?\";\n\n    String DELETE_SIMPLE_TRIGGER = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String DELETE_CRON_TRIGGER = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String DELETE_BLOB_TRIGGER = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String DELETE_TRIGGER = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_NUM_TRIGGERS_FOR_JOB = \"SELECT COUNT(\"\n            + COL_TRIGGER_NAME + \") FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \"\n            + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_JOB_FOR_TRIGGER = \"SELECT J.\"\n            + COL_JOB_NAME + \", J.\" + COL_JOB_GROUP + \", J.\" + COL_IS_DURABLE\n            + \", J.\" + COL_JOB_CLASS + \", J.\" + COL_REQUESTS_RECOVERY + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" T, \" + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS\n            + \" J WHERE T.\" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND J.\" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST \n            + \" AND T.\" + COL_TRIGGER_NAME + \" = ? AND T.\"\n            + COL_TRIGGER_GROUP + \" = ? AND T.\" + COL_JOB_NAME + \" = J.\"\n            + COL_JOB_NAME + \" AND T.\" + COL_JOB_GROUP + \" = J.\"\n            + COL_JOB_GROUP;\n\n    String SELECT_TRIGGER = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_TRIGGER_DATA = \"SELECT \" + \n            COL_JOB_DATAMAP + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n        \n    String SELECT_TRIGGER_STATE = \"SELECT \"\n            + COL_TRIGGER_STATE + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n            + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_TRIGGER_STATUS = \"SELECT \"\n            + COL_TRIGGER_STATE + \", \" + COL_NEXT_FIRE_TIME + \", \"\n            + COL_JOB_NAME + \", \" + COL_JOB_GROUP + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_SIMPLE_TRIGGER = \"SELECT *\" + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_SIMPLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_CRON_TRIGGER = \"SELECT *\" + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_CRON_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_BLOB_TRIGGER = \"SELECT *\" + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_BLOB_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_NUM_TRIGGERS = \"SELECT COUNT(\"\n            + COL_TRIGGER_NAME + \") \" + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_NUM_TRIGGERS_IN_GROUP = \"SELECT COUNT(\"\n            + COL_TRIGGER_NAME + \") \" + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_TRIGGER_GROUPS = \"SELECT DISTINCT(\"\n            + COL_TRIGGER_GROUP + \") FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_TRIGGER_GROUPS_FILTERED = \"SELECT DISTINCT(\"\n            + COL_TRIGGER_GROUP + \") FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST + \" AND \" + COL_TRIGGER_GROUP + \" LIKE ?\";\n\n    String SELECT_TRIGGERS_IN_GROUP_LIKE = \"SELECT \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" LIKE ?\";\n\n    String SELECT_TRIGGERS_IN_GROUP = \"SELECT \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String INSERT_CALENDAR = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS + \" (\" + COL_SCHEDULER_NAME + \", \" + COL_CALENDAR_NAME\n            + \", \" + COL_CALENDAR + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?)\";\n\n    String UPDATE_CALENDAR = \"UPDATE \" + TABLE_PREFIX_SUBST\n            + TABLE_CALENDARS + \" SET \" + COL_CALENDAR + \" = ? \" + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String SELECT_CALENDAR_EXISTENCE = \"SELECT \"\n            + COL_CALENDAR_NAME + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_CALENDARS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String SELECT_CALENDAR = \"SELECT *\" + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String SELECT_REFERENCED_CALENDAR = \"SELECT \"\n            + COL_CALENDAR_NAME + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String DELETE_CALENDAR = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    String SELECT_NUM_CALENDARS = \"SELECT COUNT(\"\n            + COL_CALENDAR_NAME + \") \" + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_CALENDARS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_CALENDARS = \"SELECT \" + COL_CALENDAR_NAME\n            + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_CALENDARS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_NEXT_FIRE_TIME = \"SELECT MIN(\"\n            + COL_NEXT_FIRE_TIME + \") AS \" + ALIAS_COL_NEXT_FIRE_TIME\n            + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_STATE + \" = ? AND \" + COL_NEXT_FIRE_TIME + \" >= 0\";\n\n    String SELECT_TRIGGER_FOR_FIRE_TIME = \"SELECT \"\n            + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \" FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_STATE + \" = ? AND \" + COL_NEXT_FIRE_TIME + \" = ?\";\n\n    String SELECT_NEXT_TRIGGER_TO_ACQUIRE = \"SELECT \"\n        + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \"\n        + COL_NEXT_FIRE_TIME + \", \" + COL_PRIORITY + \" FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_STATE + \" = ? AND \" + COL_NEXT_FIRE_TIME + \" <= ? \" \n        + \"AND (\" + COL_MISFIRE_INSTRUCTION + \" = -1 OR (\" +COL_MISFIRE_INSTRUCTION+ \" <> -1 AND \"+ COL_NEXT_FIRE_TIME + \" >= ?)) \"\n        + \"ORDER BY \"+ COL_NEXT_FIRE_TIME + \" ASC, \" + COL_PRIORITY + \" DESC\";\n    \n    \n    String INSERT_FIRED_TRIGGER = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" (\" + COL_SCHEDULER_NAME + \", \" + COL_ENTRY_ID\n            + \", \" + COL_TRIGGER_NAME + \", \" + COL_TRIGGER_GROUP + \", \"\n            + COL_INSTANCE_NAME + \", \"\n            + COL_FIRED_TIME + \", \" + COL_SCHED_TIME + \", \" + COL_ENTRY_STATE + \", \" + COL_JOB_NAME\n            + \", \" + COL_JOB_GROUP + \", \" + COL_IS_NONCONCURRENT + \", \"\n            + COL_REQUESTS_RECOVERY + \", \" + COL_PRIORITY\n            + \") VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\";\n\n    String UPDATE_FIRED_TRIGGER = \"UPDATE \"\n        + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" SET \" \n        + COL_INSTANCE_NAME + \" = ?, \"\n        + COL_FIRED_TIME + \" = ?, \" + COL_SCHED_TIME + \" = ?, \" + COL_ENTRY_STATE + \" = ?, \" + COL_JOB_NAME\n        + \" = ?, \" + COL_JOB_GROUP + \" = ?, \" + COL_IS_NONCONCURRENT + \" = ?, \"\n        + COL_REQUESTS_RECOVERY + \" = ? WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_ENTRY_ID + \" = ?\";\n\n    String SELECT_INSTANCES_FIRED_TRIGGERS = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_INSTANCE_NAME + \" = ?\";\n\n    String SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_INSTANCE_NAME + \" = ? AND \" + COL_REQUESTS_RECOVERY + \" = ?\";\n\n    String SELECT_JOB_EXECUTION_COUNT = \"SELECT COUNT(\"\n            + COL_TRIGGER_NAME + \") FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \"\n            + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_FIRED_TRIGGERS = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String SELECT_FIRED_TRIGGER = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_FIRED_TRIGGER_GROUP = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_FIRED_TRIGGERS_OF_JOB = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String SELECT_FIRED_TRIGGERS_OF_JOB_GROUP = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_GROUP + \" = ?\";\n\n    String DELETE_FIRED_TRIGGER = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_ENTRY_ID + \" = ?\";\n\n    String DELETE_INSTANCES_FIRED_TRIGGERS = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_FIRED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_INSTANCE_NAME + \" = ?\";\n\n    String DELETE_NO_RECOVERY_FIRED_TRIGGERS = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS\n            + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_INSTANCE_NAME + \" = ?\" + COL_REQUESTS_RECOVERY + \" = ?\";\n\n    String DELETE_ALL_SIMPLE_TRIGGERS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"SIMPLE_TRIGGERS \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_SIMPROP_TRIGGERS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"SIMPROP_TRIGGERS \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_CRON_TRIGGERS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"CRON_TRIGGERS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_BLOB_TRIGGERS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"BLOB_TRIGGERS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_TRIGGERS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"TRIGGERS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_JOB_DETAILS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"JOB_DETAILS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_CALENDARS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"CALENDARS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    String DELETE_ALL_PAUSED_TRIGGER_GRPS = \"DELETE FROM \" + TABLE_PREFIX_SUBST + \"PAUSED_TRIGGER_GRPS\" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    \n    String SELECT_FIRED_TRIGGER_INSTANCE_NAMES = \n            \"SELECT DISTINCT \" + COL_INSTANCE_NAME + \" FROM \"\n            + TABLE_PREFIX_SUBST\n            + TABLE_FIRED_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n    \n    String INSERT_SCHEDULER_STATE = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + \" (\"\n            + COL_SCHEDULER_NAME + \", \"\n            + COL_INSTANCE_NAME + \", \" + COL_LAST_CHECKIN_TIME + \", \"\n            + COL_CHECKIN_INTERVAL + \") VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?)\";\n\n    String SELECT_SCHEDULER_STATE = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_INSTANCE_NAME + \" = ?\";\n\n    String SELECT_SCHEDULER_STATES = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String DELETE_SCHEDULER_STATE = \"DELETE FROM \"\n        + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + \" WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_INSTANCE_NAME + \" = ?\";\n\n    String UPDATE_SCHEDULER_STATE = \"UPDATE \"\n        + TABLE_PREFIX_SUBST + TABLE_SCHEDULER_STATE + \" SET \" \n        + COL_LAST_CHECKIN_TIME + \" = ? WHERE \"\n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_INSTANCE_NAME + \" = ?\";\n\n    String INSERT_PAUSED_TRIGGER_GROUP = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS + \" (\"\n            + COL_SCHEDULER_NAME + \", \"\n            + COL_TRIGGER_GROUP + \") VALUES(\" + SCHED_NAME_SUBST + \", ?)\";\n\n    String SELECT_PAUSED_TRIGGER_GROUP = \"SELECT \"\n            + COL_TRIGGER_GROUP + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_PAUSED_TRIGGERS + \" WHERE \" \n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    String SELECT_PAUSED_TRIGGER_GROUPS = \"SELECT \"\n        + COL_TRIGGER_GROUP + \" FROM \" + TABLE_PREFIX_SUBST\n        + TABLE_PAUSED_TRIGGERS\n        + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    String DELETE_PAUSED_TRIGGER_GROUP = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS + \" WHERE \"\n            + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_TRIGGER_GROUP + \" LIKE ?\";\n\n    String DELETE_PAUSED_TRIGGER_GROUPS = \"DELETE FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_PAUSED_TRIGGERS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST;\n\n    //  CREATE TABLE qrtz_scheduler_state(INSTANCE_NAME VARCHAR2(80) NOT NULL,\n    // LAST_CHECKIN_TIME NUMBER(13) NOT NULL, CHECKIN_INTERVAL NUMBER(13) NOT\n    // NULL, PRIMARY KEY (INSTANCE_NAME));\n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/StdJDBCDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport static org.quartz.JobKey.jobKey;\nimport static org.quartz.TriggerBuilder.newTrigger;\nimport static org.quartz.TriggerKey.triggerKey;\nimport static org.quartz.impl.jdbcjobstore.Util.containsColumnNames;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.NotSerializableException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.math.BigDecimal;\nimport java.sql.Blob;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.Scheduler;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.JobDetailImpl;\nimport org.quartz.impl.jdbcjobstore.TriggerPersistenceDelegate.TriggerPropertyBundle;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.matchers.StringMatcher;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.OperableTrigger;\nimport org.slf4j.Logger;\n\n/**\n * <p>\n * This is meant to be an abstract base class for most, if not all, <code>{@link org.quartz.impl.jdbcjobstore.DriverDelegate}</code>\n * implementations. Subclasses should override only those methods that need\n * special handling for the DBMS driver in question.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author James House\n * @author Eric Mueller\n */\npublic class StdJDBCDelegate implements DriverDelegate, StdJDBCConstants {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger logger = null;\n\n    protected String tablePrefix = DEFAULT_TABLE_PREFIX;\n\n    protected String instanceId;\n\n    protected String schedName;\n\n    protected boolean useProperties;\n    \n    protected ClassLoadHelper classLoadHelper;\n\n    protected final List<TriggerPersistenceDelegate> triggerPersistenceDelegates = new LinkedList<>();\n\n    protected boolean useEnhancedStatements = false;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create new StdJDBCDelegate instance.\n     * </p>\n     */\n    public StdJDBCDelegate() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    /**\n     * @param initString of the format: settingName=settingValue|otherSettingName=otherSettingValue|...\n     * @throws NoSuchDelegateException \n     */\n    public void initialize(Logger logger, String tablePrefix, String schedName, String instanceId, ClassLoadHelper classLoadHelper, boolean useProperties, String initString) throws NoSuchDelegateException {\n\n        this.logger = logger;\n        this.tablePrefix = tablePrefix;\n        this.schedName = schedName;\n        this.instanceId = instanceId;\n        this.useProperties = useProperties;\n        this.classLoadHelper = classLoadHelper;\n        addDefaultTriggerPersistenceDelegates();\n\n        if(initString == null) {\n            return;\n        }\n\n        String[] settings = initString.split(\"\\\\|\");\n        \n        for(String setting: settings) {\n            String[] parts = setting.split(\"=\");\n            String name = parts[0];\n            if(parts.length == 1 || parts[1] == null || parts[1].isEmpty())\n                continue;\n\n            if(name.equals(\"triggerPersistenceDelegateClasses\")) {\n                String[] trigDelegates = parts[1].split(\",\");\n                \n                for(String trigDelClassName: trigDelegates) {\n                    try {\n                        Class<?> trigDelClass = classLoadHelper.loadClass(trigDelClassName);\n                        addTriggerPersistenceDelegate((TriggerPersistenceDelegate) trigDelClass.getDeclaredConstructor().newInstance());\n                    } catch (Exception e) {\n                        throw new NoSuchDelegateException(\"Error instantiating TriggerPersistenceDelegate of type: \" + trigDelClassName, e);\n                    } \n                }\n            }\n            else\n                throw new NoSuchDelegateException(\"Unknown setting: '\" + name + \"'\");\n        }\n    }\n\n    protected void addDefaultTriggerPersistenceDelegates() {\n        addTriggerPersistenceDelegate(new SimpleTriggerPersistenceDelegate());\n        addTriggerPersistenceDelegate(new CronTriggerPersistenceDelegate());\n        addTriggerPersistenceDelegate(new CalendarIntervalTriggerPersistenceDelegate());\n        addTriggerPersistenceDelegate(new DailyTimeIntervalTriggerPersistenceDelegate());\n    }\n\n    protected boolean canUseProperties() {\n        return useProperties;\n    }\n    \n    public void addTriggerPersistenceDelegate(TriggerPersistenceDelegate delegate) {\n        logger.debug(\"Adding TriggerPersistenceDelegate of type: {}\", delegate.getClass().getCanonicalName());\n        delegate.initialize(tablePrefix, schedName);\n        this.triggerPersistenceDelegates.add(delegate);\n    }\n    \n    public TriggerPersistenceDelegate findTriggerPersistenceDelegate(OperableTrigger trigger)  {\n        for(TriggerPersistenceDelegate delegate: triggerPersistenceDelegates) {\n            if(delegate.canHandleTriggerType(trigger))\n                return delegate;\n        }\n        \n        return null;\n    }\n\n    public TriggerPersistenceDelegate findTriggerPersistenceDelegate(String discriminator)  {\n        for(TriggerPersistenceDelegate delegate: triggerPersistenceDelegates) {\n            if(delegate.getHandledTriggerTypeDiscriminator().equals(discriminator))\n                return delegate;\n        }\n        \n        return null;\n    }\n\n    //---------------------------------------------------------------------------\n    // startup / recovery\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param newState\n     *          the new state for the triggers\n     * @param oldState1\n     *          the first old state to update\n     * @param oldState2\n     *          the second old state to update\n     * @return number of rows updated\n     */\n    public int updateTriggerStatesFromOtherStates(Connection conn,\n            String newState, String oldState1, String oldState2)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(UPDATE_TRIGGER_STATES_FROM_OTHER_STATES));\n            ps.setString(1, newState);\n            ps.setString(2, oldState1);\n            ps.setString(3, oldState2);\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the triggers that have misfired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    public List<TriggerKey> selectMisfiredTriggers(Connection conn, long ts)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS));\n            ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts)));\n            rs = ps.executeQuery();\n\n            LinkedList<TriggerKey> list = new LinkedList<>();\n            while (rs.next()) {\n                String triggerName = rs.getString(COL_TRIGGER_NAME);\n                String groupName = rs.getString(COL_TRIGGER_GROUP);\n                list.add(triggerKey(triggerName, groupName));\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the triggers in a given state.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param state\n     *          the state the triggers must be in\n     * @return an array of trigger <code>Key</code> s\n     */\n    public List<TriggerKey> selectTriggersInState(Connection conn, String state)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_STATE));\n            ps.setString(1, state);\n            rs = ps.executeQuery();\n\n            LinkedList<TriggerKey> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(triggerKey(rs.getString(1), rs.getString(2)));\n            }\n\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    public List<TriggerKey> selectMisfiredTriggersInState(Connection conn, String state,\n            long ts) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_STATE));\n            ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts)));\n            ps.setString(2, state);\n            rs = ps.executeQuery();\n\n            LinkedList<TriggerKey> list = new LinkedList<>();\n            while (rs.next()) {\n                String triggerName = rs.getString(COL_TRIGGER_NAME);\n                String groupName = rs.getString(COL_TRIGGER_GROUP);\n                list.add(triggerKey(triggerName, groupName));\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the triggers in the given state that have\n     * misfired - according to the given timestamp.  No more than count will\n     * be returned.\n     * </p>\n     * \n     * @param conn The DB Connection\n     * @param count The most misfired triggers to return, negative for all\n     * @param resultList Output parameter.  A List of \n     *      <code>{@link org.quartz.utils.Key}</code> objects.  Must not be null.\n     *          \n     * @return Whether there are more misfired triggers left to find beyond\n     *         the given count.\n     */\n    public boolean hasMisfiredTriggersInState(Connection conn, String state1, \n        long ts, int count, List<TriggerKey> resultList) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_HAS_MISFIRED_TRIGGERS_IN_STATE));\n            ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts)));\n            ps.setString(2, state1);\n            rs = ps.executeQuery();\n\n            boolean hasReachedLimit = false;\n            while (rs.next() && (!hasReachedLimit)) {\n                if (resultList.size() == count) {\n                    hasReachedLimit = true;\n                } else {\n                    String triggerName = rs.getString(COL_TRIGGER_NAME);\n                    String groupName = rs.getString(COL_TRIGGER_GROUP);\n                    resultList.add(triggerKey(triggerName, groupName));\n                }\n            }\n            \n            return hasReachedLimit;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n    \n    /**\n     * <p>\n     * Get the number of triggers in the given states that have\n     * misfired - according to the given timestamp.\n     * </p>\n     * \n     * @param conn the DB Connection\n     */\n    public int countMisfiredTriggersInState(\n            Connection conn, String state1, long ts) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(COUNT_MISFIRED_TRIGGERS_IN_STATE));\n            ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts)));\n            ps.setString(2, state1);\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return rs.getInt(1);\n            }\n\n            throw new SQLException(\"No misfired trigger count returned.\");\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the triggers in the given group and state that\n     * have misfired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link\n     * org.quartz.utils.Key}</code> objects\n     */\n    public List<TriggerKey> selectMisfiredTriggersInGroupInState(Connection conn,\n            String groupName, String state, long ts) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE));\n            ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts)));\n            ps.setString(2, groupName);\n            ps.setString(3, state);\n            rs = ps.executeQuery();\n\n            LinkedList<TriggerKey> list = new LinkedList<>();\n            while (rs.next()) {\n                String triggerName = rs.getString(COL_TRIGGER_NAME);\n                list.add(triggerKey(triggerName, groupName));\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the triggers for jobs that are requesting recovery. The\n     * returned trigger objects will have unique \"recoverXXX\" trigger names and\n     * will be in the <code>{@link\n     * org.quartz.Scheduler}.DEFAULT_RECOVERY_GROUP</code>\n     * trigger group.\n     * </p>\n     * \n     * <p>\n     * In order to preserve the ordering of the triggers, the fire time will be\n     * set from the <code>COL_FIRED_TIME</code> column in the <code>TABLE_FIRED_TRIGGERS</code>\n     * table. The caller is responsible for calling <code>computeFirstFireTime</code>\n     * on each returned trigger. It is also up to the caller to insert the\n     * returned triggers to ensure that they are fired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link org.quartz.Trigger}</code> objects\n     */\n    public List<OperableTrigger> selectTriggersForRecoveringJobs(Connection conn)\n        throws SQLException, IOException, ClassNotFoundException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS));\n            ps.setString(1, instanceId);\n            setBoolean(ps, 2, true);\n            rs = ps.executeQuery();\n\n            long dumId = System.currentTimeMillis();\n            LinkedList<OperableTrigger> list = new LinkedList<>();\n            while (rs.next()) {\n                String jobName = rs.getString(COL_JOB_NAME);\n                String jobGroup = rs.getString(COL_JOB_GROUP);\n                String trigName = rs.getString(COL_TRIGGER_NAME);\n                String trigGroup = rs.getString(COL_TRIGGER_GROUP);\n                long firedTime = rs.getLong(COL_FIRED_TIME);\n                long scheduledTime = rs.getLong(COL_SCHED_TIME);\n                int priority = rs.getInt(COL_PRIORITY);\n                @SuppressWarnings(\"deprecation\")\n                SimpleTriggerImpl rcvryTrig = new SimpleTriggerImpl(\"recover_\"\n                        + instanceId + \"_\" + dumId++,\n                        Scheduler.DEFAULT_RECOVERY_GROUP, new Date(scheduledTime));\n                rcvryTrig.setJobName(jobName);\n                rcvryTrig.setJobGroup(jobGroup);\n                rcvryTrig.setPriority(priority);\n                rcvryTrig.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n\n                JobDataMap jd = selectTriggerJobDataMap(conn, trigName, trigGroup);\n                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME, trigName);\n                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP, trigGroup);\n                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS, String.valueOf(firedTime));\n                jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS, String.valueOf(scheduledTime));\n                rcvryTrig.setJobDataMap(jd);\n                \n                list.add(rcvryTrig);\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Delete all fired triggers.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    public int deleteFiredTriggers(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_FIRED_TRIGGERS));\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int deleteFiredTriggers(Connection conn, String theInstanceId)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_INSTANCES_FIRED_TRIGGERS));\n            ps.setString(1, theInstanceId);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    \n    /**\n     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws SQLException\n     */\n    public void clearData(Connection conn)\n        throws SQLException {\n        \n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPLE_TRIGGERS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPROP_TRIGGERS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_CRON_TRIGGERS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_BLOB_TRIGGERS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_TRIGGERS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_JOB_DETAILS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_CALENDARS));\n            ps.executeUpdate();\n            ps.close();\n            ps = conn.prepareStatement(rtp(DELETE_ALL_PAUSED_TRIGGER_GRPS));\n            ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n \n    \n    //---------------------------------------------------------------------------\n    // jobs\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to insert\n     * @return number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    public int insertJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n\n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n            ps.setString(3, job.getDescription());\n            ps.setString(4, job.getJobClass().getName());\n            setBoolean(ps, 5, job.isDurable());\n            setBoolean(ps, 6, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 7, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 8, job.requestsRecovery());\n            setBytes(ps, 9, baos);\n\n            insertResult = ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Update the job detail record.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the JobDataMap\n     */\n    public int updateJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n\n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL));\n            ps.setString(1, job.getDescription());\n            ps.setString(2, job.getJobClass().getName());\n            setBoolean(ps, 3, job.isDurable());\n            setBoolean(ps, 4, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 5, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 6, job.requestsRecovery());\n            setBytes(ps, 7, baos);\n            ps.setString(8, job.getKey().getName());\n            ps.setString(9, job.getKey().getGroup());\n\n            insertResult = ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the triggers associated with the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>{@link org.quartz.utils.Key}</code> objects\n     */\n    public List<TriggerKey> selectTriggerKeysForJob(Connection conn, JobKey jobKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            LinkedList<TriggerKey> list = new LinkedList<>();\n            while (rs.next()) {\n                String trigName = rs.getString(COL_TRIGGER_NAME);\n                String trigGroup = rs.getString(COL_TRIGGER_GROUP);\n                list.add(triggerKey(trigName, trigGroup));\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Delete the job detail record for the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    public int deleteJobDetail(Connection conn, JobKey jobKey)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Deleting job: {}\", jobKey);\n            }\n            ps = conn.prepareStatement(rtp(DELETE_JOB_DETAIL));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Check whether or not the given job is stateful.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return true if the job exists and is stateful, false otherwise\n     */\n    public boolean isJobNonConcurrent(Connection conn, JobKey jobKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_NONCONCURRENT));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n            if (!rs.next()) { return false; }\n            return getBoolean(rs, COL_IS_NONCONCURRENT);\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Check whether or not the given job exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return true if the job exists, false otherwise\n     */\n    public boolean jobExists(Connection conn, JobKey jobKey)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_EXISTENCE));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Update the job data map for the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param job\n     *          the job to update\n     * @return the number of rows updated\n     */\n    public int updateJobData(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA));\n            setBytes(ps, 1, baos);\n            ps.setString(2, job.getKey().getName());\n            ps.setString(3, job.getKey().getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the JobDetail object for a given job name / group name.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the populated JobDetail object\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found or if\n     *           the job class could not be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    public JobDetail selectJobDetail(Connection conn, JobKey jobKey,\n            ClassLoadHelper loadHelper)\n        throws ClassNotFoundException, IOException, SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_DETAIL));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            JobDetailImpl job = null;\n\n            if (rs.next()) {\n                job = handleJobDetails(rs, loadHelper, true);\n            }\n\n            return job;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    public List<JobDetail> selectJobDetails(Connection conn, GroupMatcher<JobKey> matcher,\n            ClassLoadHelper loadHelper) throws ClassNotFoundException, IOException, SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            if(isMatcherEquals(matcher)) {\n                ps = conn.prepareStatement(rtp(SELECT_JOB_DETAILS));\n                ps.setString(1, toSqlEqualsClause(matcher));\n            } else {\n                ps = conn.prepareStatement(rtp(SELECT_JOB_DETAILS_LIKE));\n                ps.setString(1, toSqlLikeClause(matcher));\n            }\n            rs = ps.executeQuery();\n\n            LinkedList<JobDetail> list = new LinkedList<>();\n\n            while (rs.next()) {\n                JobDetailImpl job = handleJobDetails(rs, loadHelper, true);\n                list.add(job);\n            }\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n        /**\n         * build Map from java.util.Properties encoding.\n         */\n    private Map<?, ?> getMapFromProperties(ResultSet rs, String columnPrefix) throws ClassNotFoundException, IOException, SQLException {\n        Map<?, ?> map;\n        String colName = COL_JOB_DATAMAP;\n        if (columnPrefix != null && !columnPrefix.isEmpty()) {\n            colName = columnPrefix + COL_JOB_DATAMAP;\n        }\n        try (InputStream is = (InputStream) getJobDataFromBlob(rs, colName)) {\n            if (is == null) {\n                return null;\n            }\n            Properties properties = new Properties();\n            properties.load(is);\n            map = convertFromProperty(properties);\n        }\n        return map;\n    }\n\n    /**\n     * build Map from java.util.Properties encoding.\n     */\n    private Map<?, ?> getMapFromProperties(ResultSet rs) throws ClassNotFoundException, IOException, SQLException {\n        return getMapFromProperties(rs, null);\n    }\n\n    /**\n     * <p>\n     * Select the total number of jobs stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of jobs stored\n     */\n    public int selectNumJobs(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_JOBS));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the job group names that are stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> group names\n     */\n    public List<String> selectJobGroups(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_GROUPS));\n            rs = ps.executeQuery();\n\n            LinkedList<String> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(rs.getString(1));\n            }\n\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the jobs contained in a given group.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param matcher\n     *          the groupMatcher to evaluate the jobs against\n     * @return an array of <code>String</code> job names\n     */\n    public Set<JobKey> selectJobsInGroup(Connection conn, GroupMatcher<JobKey> matcher)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            if(isMatcherEquals(matcher)) {\n                ps = conn.prepareStatement(rtp(SELECT_JOBS_IN_GROUP));\n                ps.setString(1, toSqlEqualsClause(matcher));\n            }\n            else {\n                ps = conn.prepareStatement(rtp(SELECT_JOBS_IN_GROUP_LIKE));\n                ps.setString(1, toSqlLikeClause(matcher));\n            }\n            rs = ps.executeQuery();\n\n            LinkedList<JobKey> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(jobKey(rs.getString(1), rs.getString(2)));\n            }\n\n            return new HashSet<>(list);\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    protected boolean isMatcherEquals(final GroupMatcher<?> matcher) {\n        return matcher.getCompareWithOperator().equals(StringMatcher.StringOperatorName.EQUALS);\n    }\n\n    protected String toSqlEqualsClause(final GroupMatcher<?> matcher) {\n        return matcher.getCompareToValue();\n    }\n\n    protected String toSqlLikeClause(final GroupMatcher<?> matcher) {\n        String groupName;\n        switch(matcher.getCompareWithOperator()) {\n            case EQUALS:\n                groupName = matcher.getCompareToValue();\n                break;\n            case CONTAINS:\n                groupName = \"%\" + matcher.getCompareToValue() + \"%\";\n                break;\n            case ENDS_WITH:\n                groupName = \"%\" + matcher.getCompareToValue();\n                break;\n            case STARTS_WITH:\n                groupName = matcher.getCompareToValue() + \"%\";\n                break;\n            case ANYTHING:\n                groupName = \"%\";\n                break;\n            default:\n                throw new UnsupportedOperationException(\"Don't know how to translate \" + matcher.getCompareWithOperator() + \" into SQL\");\n        }\n        return groupName;\n    }\n\n    //---------------------------------------------------------------------------\n    // triggers\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert the base trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    public int insertTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        ByteArrayOutputStream baos = null;\n        if(!trigger.getJobDataMap().isEmpty()) {\n            baos = serializeJobData(trigger.getJobDataMap());\n        }\n        \n        PreparedStatement ps = null;\n\n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_TRIGGER));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setString(3, trigger.getJobKey().getName());\n            ps.setString(4, trigger.getJobKey().getGroup());\n            ps.setString(5, trigger.getDescription());\n            if(trigger.getNextFireTime() != null)\n                ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger\n                        .getNextFireTime().getTime())));\n            else\n                ps.setBigDecimal(6, null);\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(7, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(8, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n            ps.setString(9, type);\n            \n            ps.setBigDecimal(10, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(11, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(12, trigger.getCalendarName());\n            ps.setInt(13, trigger.getMisfireInstruction());\n            setBytes(ps, 14, baos);\n            ps.setInt(15, trigger.getPriority());\n            \n            insertResult = ps.executeUpdate();\n            \n            if(tDel == null)\n                insertBlobTrigger(conn, trigger);\n            else\n                tDel.insertExtendedTriggerProperties(conn, trigger, state, jobDetail);\n            \n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Insert the blob trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @return the number of rows inserted\n     */\n    public int insertBlobTrigger(Connection conn, OperableTrigger trigger)\n        throws SQLException, IOException {\n        PreparedStatement ps = null;\n        ByteArrayOutputStream os;\n\n        try {\n            // update the blob\n            os = new ByteArrayOutputStream();\n            ObjectOutputStream oos = new ObjectOutputStream(os);\n            oos.writeObject(trigger);\n            oos.close();\n\n            byte[] buf = os.toByteArray();\n            ByteArrayInputStream is = new ByteArrayInputStream(buf);\n\n            ps = conn.prepareStatement(rtp(INSERT_BLOB_TRIGGER));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setBinaryStream(3, is, buf.length);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update the base trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows updated\n     */\n    public int updateTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        // save some clock cycles by unnecessarily writing job data blob ...\n        boolean updateJobData = trigger.getJobDataMap().isDirty();\n        ByteArrayOutputStream baos = null;\n        if(updateJobData) {\n            baos = serializeJobData(trigger.getJobDataMap());\n        }\n                \n        PreparedStatement ps = null;\n\n        int insertResult;\n\n\n        try {\n            if(updateJobData) {\n                ps = conn.prepareStatement(rtp(UPDATE_TRIGGER));\n            } else {\n                ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_SKIP_DATA));\n            }\n                \n            ps.setString(1, trigger.getJobKey().getName());\n            ps.setString(2, trigger.getJobKey().getGroup());\n            ps.setString(3, trigger.getDescription());\n            long nextFireTime = -1;\n            if (trigger.getNextFireTime() != null) {\n                nextFireTime = trigger.getNextFireTime().getTime();\n            }\n            ps.setBigDecimal(4, new BigDecimal(String.valueOf(nextFireTime)));\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(5, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(6, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n\n            ps.setString(7, type);\n            \n            ps.setBigDecimal(8, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(9, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(10, trigger.getCalendarName());\n            ps.setInt(11, trigger.getMisfireInstruction());\n            ps.setInt(12, trigger.getPriority());\n\n            if(updateJobData) {\n                setBytes(ps, 13, baos);\n                ps.setString(14, trigger.getKey().getName());\n                ps.setString(15, trigger.getKey().getGroup());\n            } else {\n                ps.setString(13, trigger.getKey().getName());\n                ps.setString(14, trigger.getKey().getGroup());\n            }\n\n            insertResult = ps.executeUpdate();\n            \n            if(tDel == null)\n                updateBlobTrigger(conn, trigger);\n            else\n                tDel.updateExtendedTriggerProperties(conn, trigger, state, jobDetail);\n            \n        } finally {\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    /**\n     * <p>\n     * Update the blob trigger data.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger to insert\n     * @return the number of rows updated\n     */\n    public int updateBlobTrigger(Connection conn, OperableTrigger trigger)\n        throws SQLException, IOException {\n        PreparedStatement ps = null;\n\n        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n            // update the blob\n            ObjectOutputStream oos = new ObjectOutputStream(os);\n            oos.writeObject(trigger);\n            oos.close();\n\n            byte[] buf = os.toByteArray();\n            ByteArrayInputStream is = new ByteArrayInputStream(buf);\n\n            ps = conn.prepareStatement(rtp(UPDATE_BLOB_TRIGGER));\n            ps.setBinaryStream(1, is, buf.length);\n            ps.setString(2, trigger.getKey().getName());\n            ps.setString(3, trigger.getKey().getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Check whether or not a trigger exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return true if the trigger exists, false otherwise\n     */\n    public boolean triggerExists(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_EXISTENCE));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update the state for a given trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param state\n     *          the new state for the trigger\n     * @return the number of rows updated\n     */\n    public int updateTriggerState(Connection conn, TriggerKey triggerKey,\n            String state) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE));\n            ps.setString(1, state);\n            ps.setString(2, triggerKey.getName());\n            ps.setString(3, triggerKey.getGroup());\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update the given trigger to the given new state, if it is one of the\n     * given old states.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param newState\n     *          the new state for the trigger\n     * @param oldState1\n     *          one of the old state the trigger must be in\n     * @param oldState2\n     *          one of the old state the trigger must be in\n     * @param oldState3\n     *          one of the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    public int updateTriggerStateFromOtherStates(Connection conn,\n            TriggerKey triggerKey, String newState, String oldState1,\n            String oldState2, String oldState3)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE_FROM_STATES));\n            ps.setString(1, newState);\n            ps.setString(2, triggerKey.getName());\n            ps.setString(3, triggerKey.getGroup());\n            ps.setString(4, oldState1);\n            ps.setString(5, oldState2);\n            ps.setString(6, oldState3);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update all triggers in the given group to the given new state, if they\n     * are in one of the given old states.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param matcher\n     *          the groupMatcher to evaluate the triggers against\n     * @param newState\n     *          the new state for the trigger\n     * @param oldState1\n     *          one of the old state the trigger must be in\n     * @param oldState2\n     *          one of the old state the trigger must be in\n     * @param oldState3\n     *          one of the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    public int updateTriggerGroupStateFromOtherStates(Connection conn,\n            GroupMatcher<TriggerKey> matcher, String newState, String oldState1,\n            String oldState2, String oldState3) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(UPDATE_TRIGGER_GROUP_STATE_FROM_STATES));\n            ps.setString(1, newState);\n            ps.setString(2, toSqlLikeClause(matcher));\n            ps.setString(3, oldState1);\n            ps.setString(4, oldState2);\n            ps.setString(5, oldState3);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update the given trigger to the given new state, if it is in the given\n     * old state.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param newState\n     *          the new state for the trigger\n     * @param oldState\n     *          the old state the trigger must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    public int updateTriggerStateFromOtherState(Connection conn,\n            TriggerKey triggerKey, String newState, String oldState) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_TRIGGER_STATE_FROM_STATE));\n            ps.setString(1, newState);\n            ps.setString(2, triggerKey.getName());\n            ps.setString(3, triggerKey.getGroup());\n            ps.setString(4, oldState);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update all of the triggers of the given group to the given new state, if\n     * they are in the given old state.\n     * </p>\n     * \n     * @param conn\n     *          the DB connection\n     * @param matcher\n     *          the groupMatcher to evaluate the triggers against\n     * @param newState\n     *          the new state for the trigger group\n     * @param oldState\n     *          the old state the triggers must be in\n     * @return int the number of rows updated\n     * @throws SQLException\n     */\n    public int updateTriggerGroupStateFromOtherState(Connection conn,\n            GroupMatcher<TriggerKey> matcher, String newState, String oldState)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(UPDATE_TRIGGER_GROUP_STATE_FROM_STATE));\n            ps.setString(1, newState);\n            ps.setString(2, toSqlLikeClause(matcher));\n            ps.setString(3, oldState);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update the states of all triggers associated with the given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param state\n     *          the new state for the triggers\n     * @return the number of rows updated\n     */\n    public int updateTriggerStatesForJob(Connection conn, JobKey jobKey,\n            String state) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_JOB_TRIGGER_STATES));\n            ps.setString(1, state);\n            ps.setString(2, jobKey.getName());\n            ps.setString(3, jobKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int updateTriggerStatesForJobFromOtherState(Connection conn,\n            JobKey jobKey, String state, String oldState)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn\n                    .prepareStatement(rtp(UPDATE_JOB_TRIGGER_STATES_FROM_OTHER_STATE));\n            ps.setString(1, state);\n            ps.setString(2, jobKey.getName());\n            ps.setString(3, jobKey.getGroup());\n            ps.setString(4, oldState);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Delete the cron trigger data for a trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    public int deleteBlobTrigger(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_BLOB_TRIGGER));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Delete the base trigger data for a trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of rows deleted\n     */\n    public int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n\n        deleteTriggerExtension(conn, triggerKey);\n        \n        try {\n            ps = conn.prepareStatement(rtp(DELETE_TRIGGER));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n    \n    protected void deleteTriggerExtension(Connection conn, TriggerKey triggerKey) throws SQLException {\n\n        for(TriggerPersistenceDelegate tDel: triggerPersistenceDelegates) {\n            if(tDel.deleteExtendedTriggerProperties(conn, triggerKey) > 0) {\n                return; // as soon as one affects a row, we're done.\n            }\n        }\n        \n        deleteBlobTrigger(conn, triggerKey); \n    }\n\n    /**\n     * <p>\n     * Select the number of triggers associated with a given job.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the number of triggers for the given job\n     */\n    public int selectNumTriggersForJob(Connection conn, JobKey jobKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS_FOR_JOB));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return rs.getInt(1);\n            } else {\n                return 0;\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the job to which the trigger is associated.\n     * </p>\n     *\n     * @param conn\n     *          the DB Connection\n     * @return the <code>{@link org.quartz.JobDetail}</code> object\n     *         associated with the given trigger\n     * @throws SQLException\n     * @throws ClassNotFoundException\n     */\n    public JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper,\n        TriggerKey triggerKey) throws ClassNotFoundException, SQLException, IOException {\n        return selectJobForTrigger(conn, loadHelper, triggerKey, true);\n    }\n\n    private JobDetailImpl handleJobDetails(ResultSet rs, ClassLoadHelper loadHelper, boolean loadJobClass)\n        throws SQLException, ClassNotFoundException, IOException {\n\n        JobDetailImpl job = new JobDetailImpl();\n        job.setName(rs.getString(COL_JOB_NAME));\n        job.setGroup(rs.getString(COL_JOB_GROUP));\n        if (containsColumnNames(rs, COL_DESCRIPTION)) {\n            job.setDescription(rs.getString(COL_DESCRIPTION));\n        }\n        job.setDurability(rs.getBoolean(COL_IS_DURABLE));\n        if (loadJobClass) {\n            job.setJobClass(loadHelper.loadClass(rs.getString(COL_JOB_CLASS), Job.class));\n        }\n        job.setRequestsRecovery(rs.getBoolean(COL_REQUESTS_RECOVERY));\n        if (containsColumnNames(rs, COL_JOB_DATAMAP) || containsColumnNames(rs, COL_JOB_DATAMAP)) {\n            Map<?, ?> map = null;\n            if (canUseProperties()) {\n                if (containsColumnNames(rs,  COL_JOB_DATAMAP)) {\n                    map = getMapFromProperties(rs);\n                }\n            } else {\n                if (containsColumnNames(rs, COL_JOB_DATAMAP)) {\n                    map = (Map<?, ?>) getObjectFromBlob(rs, COL_JOB_DATAMAP);\n                }\n            }\n\n            if (null != map) {\n                job.setJobDataMap(new JobDataMap(map));\n            }\n        }\n\n        return job;\n    }\n\n    /**\n     * <p>\n     * Select the job to which the trigger is associated. Allow option to load actual job class or not. When case of\n     * remove, we do not need to load the class, which in many cases, it's no longer exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the {@link org.quartz.JobDetail} object\n     *         associated with the given trigger\n     * @throws SQLException\n     * @throws ClassNotFoundException\n     */\n    public JobDetail selectJobForTrigger(Connection conn, ClassLoadHelper loadHelper,\n            TriggerKey triggerKey, boolean loadJobClass) throws ClassNotFoundException, SQLException, IOException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_FOR_TRIGGER));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return handleJobDetails(rs, loadHelper, loadJobClass);\n            } else {\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"No job for trigger '{}'.\", triggerKey);\n                }\n                return null;\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the triggers for a job\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of {@link org.quartz.Trigger} objects\n     *         associated with a given job.\n     * @throws SQLException\n     * @throws JobPersistenceException \n     */\n    public List<OperableTrigger> selectTriggersForJob(Connection conn, JobKey jobKey) throws SQLException,\n        ClassNotFoundException, IOException, JobPersistenceException {\n\n\n        if (useEnhancedStatements) {\n            return selectBulkTriggersForJob(conn, jobKey);\n        }\n\n        LinkedList<OperableTrigger> trigList = new LinkedList<>();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                OperableTrigger t = selectTrigger(conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP)));\n                if(t != null) {\n                    trigList.add(t);\n                }\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return trigList;\n    }\n\n    protected List<OperableTrigger> selectBulkTriggersForJob(Connection conn, JobKey jobKey) throws SQLException,\n        ClassNotFoundException, IOException, JobPersistenceException {\n        LinkedList<OperableTrigger> trigList = new LinkedList<>();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB_V2));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                trigList.add(handleTriggerV2(rs, conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))));\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return trigList;\n    }\n\n    public List<OperableTrigger> selectTriggersForCalendar(Connection conn, String calName)\n        throws SQLException, ClassNotFoundException, IOException, JobPersistenceException {\n        if(useEnhancedStatements) {\n            return selectBulkTriggersForCalendar(conn, calName);\n        }\n\n        LinkedList<OperableTrigger> trigList = new LinkedList<>();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_CALENDAR));\n            ps.setString(1, calName);\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                trigList.add(selectTrigger(conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))));\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return trigList;\n    }\n\n    protected List<OperableTrigger> selectBulkTriggersForCalendar(Connection conn, String calName)\n        throws SQLException, ClassNotFoundException, IOException, JobPersistenceException {\n        LinkedList<OperableTrigger> trigList = new LinkedList<>();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_CALENDAR_V2));\n            ps.setString(1, calName);\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                trigList.add(handleTriggerV2(rs, conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))));\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return trigList;\n    }\n\n    public List<OperableTrigger> getTriggersByJobAndTriggerGroup(Connection conn, GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws SQLException, ClassNotFoundException,\n        IOException, JobPersistenceException {\n\n        String baseStatement = SELECT_BULK_TRIGGERS_BASE;\n        boolean hasMatcher = false;\n        List<PreparedStatementConsumer> columnSetters = new LinkedList<>();\n\n        if (jobMatcher == null) {\n            throw new IllegalArgumentException(\"jobMatcher cannot be null\");\n        }\n\n        if (triggerMatcher == null) {\n            throw new IllegalArgumentException(\"triggerMatcher cannot be null\");\n        }\n\n        if (jobMatcher.getCompareWithOperator() != StringMatcher.StringOperatorName.ANYTHING) {\n            baseStatement += \" WHERE \" + \"T.\" + COL_JOB_GROUP;\n            hasMatcher = true;\n            if (isMatcherEquals(jobMatcher)) {\n                baseStatement += \" = ?\";\n                columnSetters.add(ps -> ps.setString(1, toSqlEqualsClause(jobMatcher)));\n            } else {\n                baseStatement += \" LIKE ?\";\n                columnSetters.add(ps -> ps.setString(1, toSqlLikeClause(jobMatcher)));\n            }\n        }\n\n        if (triggerMatcher.getCompareWithOperator() != StringMatcher.StringOperatorName.ANYTHING) {\n            final int columnIndex = hasMatcher ? 2 : 1;\n            if (hasMatcher) {\n                baseStatement += \"\\n AND \";\n            } else {\n                baseStatement += \"\\n WHERE \";\n            }\n            baseStatement += \"T.\" + COL_TRIGGER_GROUP;\n            if (isMatcherEquals(triggerMatcher)) {\n                baseStatement += \" = ?\";\n                columnSetters.add(ps -> ps.setString(columnIndex, toSqlEqualsClause(triggerMatcher)));\n            } else {\n                baseStatement += \" LIKE ?\";\n                columnSetters.add(ps -> ps.setString(columnIndex, toSqlLikeClause(triggerMatcher)));\n            }\n        }\n\n        LinkedList<OperableTrigger> trigList = new LinkedList<>();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(baseStatement));\n            for (PreparedStatementConsumer setter : columnSetters) {\n                setter.accept(ps);\n            }\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                trigList.add(handleTriggerV2(rs, conn, triggerKey(rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))));\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return trigList;\n    }\n\n\n    private OperableTrigger handleTrigger(ResultSet rs, Connection conn, TriggerKey triggerKey, PreparedStatement ps)\n        throws SQLException, ClassNotFoundException, IOException, JobPersistenceException {\n        OperableTrigger trigger = null;\n        String jobName = rs.getString(COL_JOB_NAME);\n        String jobGroup = rs.getString(COL_JOB_GROUP);\n        String description = rs.getString(COL_DESCRIPTION);\n        long nextFireTime = rs.getLong(COL_NEXT_FIRE_TIME);\n        long prevFireTime = rs.getLong(COL_PREV_FIRE_TIME);\n        String triggerType = rs.getString(COL_TRIGGER_TYPE);\n        long startTime = rs.getLong(COL_START_TIME);\n        long endTime = rs.getLong(COL_END_TIME);\n        String calendarName = rs.getString(COL_CALENDAR_NAME);\n        int misFireInstr = rs.getInt(COL_MISFIRE_INSTRUCTION);\n        int priority = rs.getInt(COL_PRIORITY);\n\n        Map<?, ?> map;\n        if (canUseProperties()) {\n            map = getMapFromProperties(rs);\n        } else {\n            map = (Map<?, ?>) getObjectFromBlob(rs, COL_JOB_DATAMAP);\n        }\n\n        Date nft = null;\n        if (nextFireTime > 0) {\n            nft = new Date(nextFireTime);\n        }\n\n        Date pft = null;\n        if (prevFireTime > 0) {\n            pft = new Date(prevFireTime);\n        }\n        Date startTimeD = new Date(startTime);\n        Date endTimeD = null;\n        if (endTime > 0) {\n            endTimeD = new Date(endTime);\n        }\n\n        if (triggerType.equals(TTYPE_BLOB)) {\n            try (PreparedStatement pps = conn.prepareStatement(rtp(SELECT_BLOB_TRIGGER))) {\n                pps.setString(1, triggerKey.getName());\n                pps.setString(2, triggerKey.getGroup());\n                ResultSet rss = pps.executeQuery();\n\n                if (rss.next()) {\n                    trigger = (OperableTrigger) getObjectFromBlob(rs, COL_BLOB);\n                }\n            }\n        } else {\n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(triggerType);\n\n            if(tDel == null){\n                throw new JobPersistenceException(\"No TriggerPersistenceDelegate for trigger discriminator type: \" + triggerType);\n            }\n\n            TriggerPropertyBundle triggerProps;\n            try {\n                triggerProps = tDel.loadExtendedTriggerProperties(conn, triggerKey);\n            } catch (IllegalStateException isex) {\n                if (isTriggerStillPresent(ps)) {\n                    throw isex;\n                } else {\n                    // QTZ-386 Trigger has been deleted\n                    return null;\n                }\n            }\n\n            TriggerBuilder<?> tb = newTrigger()\n                .withDescription(description)\n                .withPriority(priority)\n                .startAt(startTimeD)\n                .endAt(endTimeD)\n                .withIdentity(triggerKey)\n                .modifiedByCalendar(calendarName)\n                .withSchedule(triggerProps.getScheduleBuilder())\n                .forJob(jobKey(jobName, jobGroup));\n\n            if (null != map) {\n                tb.usingJobData(new JobDataMap(map));\n            }\n\n            trigger = (OperableTrigger) tb.build();\n\n            trigger.setMisfireInstruction(misFireInstr);\n            trigger.setNextFireTime(nft);\n            trigger.setPreviousFireTime(pft);\n\n            setTriggerStateProperties(trigger, triggerProps);\n        }\n        return trigger;\n    }\n\n    private OperableTrigger handleTriggerV2(ResultSet rs, Connection conn, TriggerKey triggerKey)\n    throws SQLException, ClassNotFoundException, IOException, JobPersistenceException {\n        OperableTrigger trigger = null;\n        String jobName = rs.getString(COL_JOB_NAME);\n        String jobGroup = rs.getString(COL_JOB_GROUP);\n        String description = rs.getString(COL_DESCRIPTION);\n        long nextFireTime = rs.getLong(COL_NEXT_FIRE_TIME);\n        long prevFireTime = rs.getLong(COL_PREV_FIRE_TIME);\n        String triggerType = rs.getString(COL_TRIGGER_TYPE);\n        long startTime = rs.getLong(COL_START_TIME);\n        long endTime = rs.getLong(COL_END_TIME);\n        String calendarName = rs.getString(COL_CALENDAR_NAME);\n        int misFireInstr = rs.getInt(COL_MISFIRE_INSTRUCTION);\n        int priority = rs.getInt(COL_PRIORITY);\n\n        Map<?, ?> map;\n        if (canUseProperties()) {\n            map = getMapFromProperties(rs);\n        } else {\n            map = (Map<?, ?>) getObjectFromBlob(rs, COL_JOB_DATAMAP);\n        }\n\n        Date nft = null;\n        if (nextFireTime > 0) {\n            nft = new Date(nextFireTime);\n        }\n\n        Date pft = null;\n        if (prevFireTime > 0) {\n            pft = new Date(prevFireTime);\n        }\n        Date startTimeD = new Date(startTime);\n        Date endTimeD = null;\n        if (endTime > 0) {\n            endTimeD = new Date(endTime);\n        }\n\n        if (triggerType.equals(TTYPE_BLOB)) {\n            if (containsColumnNames(rs, COL_JOB_DATAMAP)) {\n                trigger = (OperableTrigger) getObjectFromBlob(rs, COL_BLOB);\n            }\n        } else {\n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(triggerType);\n\n            if(tDel == null) {\n                throw new JobPersistenceException(\"No TriggerPersistenceDelegate for trigger discriminator type: \" + triggerType);\n            }\n\n            TriggerPropertyBundle triggerProps;\n            if (tDel.hasInlinedResultSetProperties()) {\n                triggerProps = tDel.loadExtendedTriggerPropertiesFromResultSet(rs, triggerKey);\n            } else {\n                //this is the old way, in case we have to load the trigger properties from the database\n                triggerProps = tDel.loadExtendedTriggerProperties(conn, triggerKey);\n            }\n\n            TriggerBuilder<?> tb = newTrigger()\n                .withDescription(description)\n                .withPriority(priority)\n                .startAt(startTimeD)\n                .endAt(endTimeD)\n                .withIdentity(triggerKey)\n                .modifiedByCalendar(calendarName)\n                .withSchedule(triggerProps.getScheduleBuilder())\n                .forJob(jobKey(jobName, jobGroup));\n\n            if (null != map) {\n                tb.usingJobData(new JobDataMap(map));\n            }\n\n            trigger = (OperableTrigger) tb.build();\n\n            trigger.setMisfireInstruction(misFireInstr);\n            trigger.setNextFireTime(nft);\n            trigger.setPreviousFireTime(pft);\n\n            setTriggerStateProperties(trigger, triggerProps);\n        }\n        return trigger;\n    }\n\n    /**\n     * <p>\n     * Select a trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the <code>{@link org.quartz.Trigger}</code> object\n     * @throws JobPersistenceException \n     */\n    public OperableTrigger selectTrigger(Connection conn, TriggerKey triggerKey) throws SQLException, ClassNotFoundException,\n            IOException, JobPersistenceException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return handleTrigger(rs, conn, triggerKey, ps);\n            }\n            return null;\n        } catch (NoRecordFoundException nrfe) {\n            if (isTriggerStillPresent(ps)) {\n                throw nrfe;\n            } else {\n                // QTZ-386 Trigger has been deleted\n                return null;\n            }\n        } catch (IOException ioex) {\n            throw new JobPersistenceException(\"Error serializing trigger: \" + triggerKey, ioex);\n        }\n        finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    private boolean isTriggerStillPresent(PreparedStatement ps) throws SQLException {\n        ResultSet rs = null;\n        try {\n            rs = ps.executeQuery();\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n        }\n    }\n\n    private void setTriggerStateProperties(OperableTrigger trigger, TriggerPropertyBundle props) throws JobPersistenceException {\n        \n        if(props.getStatePropertyNames() == null)\n            return;\n        \n        Util.setBeanProps(trigger, props.getStatePropertyNames(), props.getStatePropertyValues());\n    }\n\n    /**\n     * <p>\n     * Select a trigger's JobDataMap.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param triggerName\n     *          the name of the trigger\n     * @param groupName\n     *          the group containing the trigger\n     * @return the <code>{@link org.quartz.JobDataMap}</code> of the Trigger,\n     * never null, but possibly empty.\n     */\n    public JobDataMap selectTriggerJobDataMap(Connection conn, String triggerName,\n            String groupName) throws SQLException, ClassNotFoundException,\n            IOException {\n        \n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_DATA));\n            ps.setString(1, triggerName);\n            ps.setString(2, groupName);\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n\n                Map<?, ?> map;\n                if (canUseProperties()) { \n                    map = getMapFromProperties(rs);\n                } else {\n                    map = (Map<?, ?>) getObjectFromBlob(rs, COL_JOB_DATAMAP);\n                }\n                \n                rs.close();\n                ps.close();\n\n                if (null != map) {\n                    return new JobDataMap(map);\n                }\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n        \n        return new JobDataMap();\n    }\n            \n\n    /**\n     * <p>\n     * Select a trigger' state value.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the <code>{@link org.quartz.Trigger}</code> object\n     */\n    public String selectTriggerState(Connection conn, TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            String state;\n\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_STATE));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                state = rs.getString(COL_TRIGGER_STATE);\n            } else {\n                state = STATE_DELETED;\n            }\n\n            return state.intern();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Select a trigger' status (state and next fire time).\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return a <code>TriggerStatus</code> object, or null\n     */\n    public TriggerStatus selectTriggerStatus(Connection conn,\n            TriggerKey triggerKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            TriggerStatus status = null;\n\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_STATUS));\n            ps.setString(1, triggerKey.getName());\n            ps.setString(2, triggerKey.getGroup());\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                String state = rs.getString(COL_TRIGGER_STATE);\n                long nextFireTime = rs.getLong(COL_NEXT_FIRE_TIME);\n                String jobName = rs.getString(COL_JOB_NAME);\n                String jobGroup = rs.getString(COL_JOB_GROUP);\n\n                Date nft = null;\n                if (nextFireTime > 0) {\n                    nft = new Date(nextFireTime);\n                }\n\n                status = new TriggerStatus(state, nft);\n                status.setKey(triggerKey);\n                status.setJobKey(jobKey(jobName, jobGroup));\n            }\n\n            return status;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    /**\n     * <p>\n     * Select the total number of triggers stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of triggers stored\n     */\n    public int selectNumTriggers(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the trigger group names that are stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> group names\n     */\n    public List<String> selectTriggerGroups(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_GROUPS));\n            rs = ps.executeQuery();\n\n            LinkedList<String> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(rs.getString(1));\n            }\n\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    public List<String> selectTriggerGroups(Connection conn, GroupMatcher<TriggerKey> matcher) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_GROUPS_FILTERED));\n            ps.setString(1, toSqlLikeClause(matcher));\n            rs = ps.executeQuery();\n\n            LinkedList<String> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(rs.getString(1));\n            }\n\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the triggers contained in a given group.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param matcher\n     *          to evaluate against known triggers\n     * @return a Set of <code>TriggerKey</code>s\n     */\n    public Set<TriggerKey> selectTriggersInGroup(Connection conn, GroupMatcher<TriggerKey> matcher)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            if(isMatcherEquals(matcher)) {\n                ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_GROUP));\n                ps.setString(1, toSqlEqualsClause(matcher));\n            }\n            else {\n                ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_GROUP_LIKE));\n                ps.setString(1, toSqlLikeClause(matcher));\n            }\n            rs = ps.executeQuery();\n\n            Set<TriggerKey> keys = new HashSet<>();\n            while (rs.next()) {\n                keys.add(triggerKey(rs.getString(1), rs.getString(2)));\n            }\n\n            return keys;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    public int insertPausedTriggerGroup(Connection conn, String groupName)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_PAUSED_TRIGGER_GROUP));\n            ps.setString(1, groupName);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int deletePausedTriggerGroup(Connection conn, String groupName)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_PAUSED_TRIGGER_GROUP));\n            ps.setString(1, groupName);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int deletePausedTriggerGroup(Connection conn, GroupMatcher<TriggerKey> matcher)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_PAUSED_TRIGGER_GROUP));\n            ps.setString(1, toSqlLikeClause(matcher));\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int deleteAllPausedTriggerGroups(Connection conn)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_PAUSED_TRIGGER_GROUPS));\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public boolean isTriggerGroupPaused(Connection conn, String groupName)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_PAUSED_TRIGGER_GROUP));\n            ps.setString(1, groupName);\n            rs = ps.executeQuery();\n\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    public boolean isExistingTriggerGroup(Connection conn, String groupName)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_NUM_TRIGGERS_IN_GROUP));\n            ps.setString(1, groupName);\n            rs = ps.executeQuery();\n\n            if (!rs.next()) {\n                return false;\n            }\n\n            return (rs.getInt(1) > 0);\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    //---------------------------------------------------------------------------\n    // calendars\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Insert a new calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows inserted\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    public int insertCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeObject(calendar);\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_CALENDAR));\n            ps.setString(1, calendarName);\n            setBytes(ps, 2, baos);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name for the new calendar\n     * @param calendar\n     *          the calendar\n     * @return the number of rows updated\n     * @throws IOException\n     *           if there were problems serializing the calendar\n     */\n    public int updateCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeObject(calendar);\n\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_CALENDAR));\n            setBytes(ps, 1, baos);\n            ps.setString(2, calendarName);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Check whether or not a calendar exists.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return true if the trigger exists, false otherwise\n     */\n    public boolean calendarExists(Connection conn, String calendarName)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_CALENDAR_EXISTENCE));\n            ps.setString(1, calendarName);\n            rs = ps.executeQuery();\n\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return the Calendar\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found be\n     *           found\n     * @throws IOException\n     *           if there were problems deserializing the calendar\n     */\n    public Calendar selectCalendar(Connection conn, String calendarName)\n        throws ClassNotFoundException, IOException, SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            String selCal = rtp(SELECT_CALENDAR);\n            ps = conn.prepareStatement(selCal);\n            ps.setString(1, calendarName);\n            rs = ps.executeQuery();\n\n            Calendar cal = null;\n            if (rs.next()) {\n                cal = (Calendar) getObjectFromBlob(rs, COL_CALENDAR);\n            }\n            if (null == cal) {\n                logger.warn(\"Couldn't find calendar with name '{}'.\", calendarName);\n            }\n            return cal;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Check whether or not a calendar is referenced by any triggers.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the calendar\n     * @return true if any triggers reference the calendar, false otherwise\n     */\n    public boolean calendarIsReferenced(Connection conn, String calendarName)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_REFERENCED_CALENDAR));\n            ps.setString(1, calendarName);\n            rs = ps.executeQuery();\n\n            return rs.next();\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Delete a calendar.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param calendarName\n     *          the name of the trigger\n     * @return the number of rows deleted\n     */\n    public int deleteCalendar(Connection conn, String calendarName)\n        throws SQLException {\n        PreparedStatement ps = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_CALENDAR));\n            ps.setString(1, calendarName);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the total number of calendars stored.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the total number of calendars stored\n     */\n    public int selectNumCalendars(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            int count = 0;\n            ps = conn.prepareStatement(rtp(SELECT_NUM_CALENDARS));\n\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                count = rs.getInt(1);\n            }\n\n            return count;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select all of the stored calendars.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return an array of <code>String</code> calendar names\n     */\n    public List<String> selectCalendars(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_CALENDARS));\n            rs = ps.executeQuery();\n\n            LinkedList<String> list = new LinkedList<>();\n            while (rs.next()) {\n                list.add(rs.getString(1));\n            }\n\n            return list;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    //---------------------------------------------------------------------------\n    // trigger firing\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Select the next time that a trigger will be fired.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @return the next fire time, or 0 if no trigger will be fired\n     * \n     * @deprecated Does not account for misfires.\n     */\n    @Deprecated\n    public long selectNextFireTime(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_NEXT_FIRE_TIME));\n            ps.setString(1, STATE_WAITING);\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return rs.getLong(ALIAS_COL_NEXT_FIRE_TIME);\n            } else {\n                return 0L;\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the trigger that will be fired at the given fire time.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param fireTime\n     *          the time that the trigger will be fired\n     * @return a <code>{@link org.quartz.utils.Key}</code> representing the\n     *         trigger that will be fired at the given fire time, or null if no\n     *         trigger will be fired at that time\n     */\n    public TriggerKey selectTriggerForFireTime(Connection conn, long fireTime)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_TRIGGER_FOR_FIRE_TIME));\n            ps.setString(1, STATE_WAITING);\n            ps.setBigDecimal(2, new BigDecimal(String.valueOf(fireTime)));\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                return new TriggerKey(rs.getString(COL_TRIGGER_NAME), rs\n                        .getString(COL_TRIGGER_GROUP));\n            } else {\n                return null;\n            }\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n\n    \n    /**\n     * <p>\n     * Select the next trigger which will fire to fire between the two given timestamps \n     * in ascending order of fire time, and then descending by priority.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param noLaterThan\n     *          highest value of <code>getNextFireTime()</code> of the triggers (exclusive)\n     * @param noEarlierThan \n     *          highest value of <code>getNextFireTime()</code> of the triggers (inclusive)\n     *          \n     * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired.\n     * \n     * @deprecated - This remained for compatibility reason. Use {@link #selectTriggerToAcquire(Connection, long, long, int)} instead. \n     */\n    @Deprecated\n    public List<TriggerKey> selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan)\n            throws SQLException {\n        // This old API used to always return 1 trigger.\n        return selectTriggerToAcquire(conn, noLaterThan, noEarlierThan, 1);\n    }\n\n    /**\n     * <p>\n     * Select the next trigger which will fire to fire between the two given timestamps \n     * in ascending order of fire time, and then descending by priority.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param noLaterThan\n     *          highest value of <code>getNextFireTime()</code> of the triggers (exclusive)\n     * @param noEarlierThan \n     *          highest value of <code>getNextFireTime()</code> of the triggers (inclusive)\n     * @param maxCount \n     *          maximum number of trigger keys allow to acquired in the returning list.\n     *          \n     * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired.\n     */\n    public List<TriggerKey> selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan, int maxCount)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        List<TriggerKey> nextTriggers = new LinkedList<>();\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_NEXT_TRIGGER_TO_ACQUIRE));\n            \n            // Set max rows to retrieve\n            if (maxCount < 1)\n                maxCount = 1; // we want at least one trigger back.\n            ps.setMaxRows(maxCount);\n            \n            // Try to give jdbc driver a hint to hopefully not pull over more than the few rows we actually need.\n            // Note: in some jdbc drivers, such as MySQL, you must set maxRows before fetchSize, or you get exception!\n            ps.setFetchSize(maxCount);\n            \n            ps.setString(1, STATE_WAITING);\n            ps.setBigDecimal(2, new BigDecimal(String.valueOf(noLaterThan)));\n            ps.setBigDecimal(3, new BigDecimal(String.valueOf(noEarlierThan)));\n            rs = ps.executeQuery();\n            \n            while (rs.next() && nextTriggers.size() < maxCount) {\n                nextTriggers.add(triggerKey(\n                        rs.getString(COL_TRIGGER_NAME),\n                        rs.getString(COL_TRIGGER_GROUP)));\n            }\n            \n            return nextTriggers;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }      \n    }\n\n    /**\n     * <p>\n     * Insert a fired trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    public int insertFiredTrigger(Connection conn, OperableTrigger trigger,\n            String state, JobDetail job) throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_FIRED_TRIGGER));\n            ps.setString(1, trigger.getFireInstanceId());\n            ps.setString(2, trigger.getKey().getName());\n            ps.setString(3, trigger.getKey().getGroup());\n            ps.setString(4, instanceId);\n            ps.setBigDecimal(5, new BigDecimal(String.valueOf(System.currentTimeMillis())));\n            ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger.getNextFireTime().getTime())));\n            ps.setString(7, state);\n            if (job != null) {\n                ps.setString(8, trigger.getJobKey().getName());\n                ps.setString(9, trigger.getJobKey().getGroup());\n                setBoolean(ps, 10, job.isConcurrentExecutionDisallowed());\n                setBoolean(ps, 11, job.requestsRecovery());\n            } else {\n                ps.setString(8, null);\n                ps.setString(9, null);\n                setBoolean(ps, 10, false);\n                setBoolean(ps, 11, false);\n            }\n            ps.setInt(12, trigger.getPriority());\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Update a fired trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param trigger\n     *          the trigger\n     * @param state\n     *          the state that the trigger should be stored in\n     * @return the number of rows inserted\n     */\n    public int updateFiredTrigger(Connection conn, OperableTrigger trigger,\n            String state, JobDetail job) throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_FIRED_TRIGGER));\n            \n            ps.setString(1, instanceId);\n\n            ps.setBigDecimal(2, new BigDecimal(String.valueOf(System.currentTimeMillis())));\n            ps.setBigDecimal(3, new BigDecimal(String.valueOf(trigger.getNextFireTime().getTime())));\n            ps.setString(4, state);\n\n            if (job != null) {\n                ps.setString(5, trigger.getJobKey().getName());\n                ps.setString(6, trigger.getJobKey().getGroup());\n                setBoolean(ps, 7, job.isConcurrentExecutionDisallowed());\n                setBoolean(ps, 8, job.requestsRecovery());\n            } else {\n                ps.setString(5, null);\n                ps.setString(6, null);\n                setBoolean(ps, 7, false);\n                setBoolean(ps, 8, false);\n            }\n\n            ps.setString(9, trigger.getFireInstanceId());\n\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n    \n    /**\n     * <p>\n     * Select the states of all fired-trigger records for a given trigger, or\n     * trigger group if trigger name is <code>null</code>.\n     * </p>\n     * \n     * @return a List of FiredTriggerRecord objects.\n     */\n    public List<FiredTriggerRecord> selectFiredTriggerRecords(Connection conn, String triggerName, String groupName) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            List<FiredTriggerRecord> lst = new LinkedList<>();\n\n            if (triggerName != null) {\n                ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER));\n                ps.setString(1, triggerName);\n                ps.setString(2, groupName);\n            } else {\n                ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER_GROUP));\n                ps.setString(1, groupName);\n            }\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                FiredTriggerRecord rec = new FiredTriggerRecord();\n\n                rec.setFireInstanceId(rs.getString(COL_ENTRY_ID));\n                rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE));\n                rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME));\n                rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME));\n                rec.setPriority(rs.getInt(COL_PRIORITY));\n                rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME));\n                rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs\n                        .getString(COL_TRIGGER_GROUP)));\n                if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) {\n                    rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT));\n                    rec.setJobRequestsRecovery(rs\n                            .getBoolean(COL_REQUESTS_RECOVERY));\n                    rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs\n                            .getString(COL_JOB_GROUP)));\n                }\n                lst.add(rec);\n            }\n\n            return lst;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the states of all fired-trigger records for a given job, or job\n     * group if job name is <code>null</code>.\n     * </p>\n     * \n     * @return a List of FiredTriggerRecord objects.\n     */\n    public List<FiredTriggerRecord> selectFiredTriggerRecordsByJob(Connection conn, String jobName, String groupName) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            List<FiredTriggerRecord> lst = new LinkedList<>();\n\n            if (jobName != null) {\n                ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGERS_OF_JOB));\n                ps.setString(1, jobName);\n                ps.setString(2, groupName);\n            } else {\n                ps = conn\n                        .prepareStatement(rtp(SELECT_FIRED_TRIGGERS_OF_JOB_GROUP));\n                ps.setString(1, groupName);\n            }\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                FiredTriggerRecord rec = new FiredTriggerRecord();\n\n                rec.setFireInstanceId(rs.getString(COL_ENTRY_ID));\n                rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE));\n                rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME));\n                rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME));\n                rec.setPriority(rs.getInt(COL_PRIORITY));\n                rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME));\n                rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs\n                        .getString(COL_TRIGGER_GROUP)));\n                if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) {\n                    rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT));\n                    rec.setJobRequestsRecovery(rs\n                            .getBoolean(COL_REQUESTS_RECOVERY));\n                    rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs\n                            .getString(COL_JOB_GROUP)));\n                }\n                lst.add(rec);\n            }\n\n            return lst;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    public List<FiredTriggerRecord> selectInstancesFiredTriggerRecords(Connection conn,\n            String instanceName) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            List<FiredTriggerRecord> lst = new LinkedList<>();\n\n            ps = conn.prepareStatement(rtp(SELECT_INSTANCES_FIRED_TRIGGERS));\n            ps.setString(1, instanceName);\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                FiredTriggerRecord rec = new FiredTriggerRecord();\n\n                rec.setFireInstanceId(rs.getString(COL_ENTRY_ID));\n                rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE));\n                rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME));\n                rec.setScheduleTimestamp(rs.getLong(COL_SCHED_TIME));\n                rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME));\n                rec.setTriggerKey(triggerKey(rs.getString(COL_TRIGGER_NAME), rs\n                        .getString(COL_TRIGGER_GROUP)));\n                if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) {\n                    rec.setJobDisallowsConcurrentExecution(getBoolean(rs, COL_IS_NONCONCURRENT));\n                    rec.setJobRequestsRecovery(rs\n                            .getBoolean(COL_REQUESTS_RECOVERY));\n                    rec.setJobKey(jobKey(rs.getString(COL_JOB_NAME), rs\n                            .getString(COL_JOB_GROUP)));\n                }\n                rec.setPriority(rs.getInt(COL_PRIORITY));\n                lst.add(rec);\n            }\n\n            return lst;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * <p>\n     * Select the distinct instance names of all fired-trigger records.\n     * </p>\n     * \n     * <p>\n     * This is useful when trying to identify orphaned fired triggers (a \n     * fired trigger without a scheduler state record.) \n     * </p>\n     * \n     * @return a Set of String objects.\n     */\n    public Set<String> selectFiredTriggerInstanceNames(Connection conn) \n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            Set<String> instanceNames = new HashSet<>();\n\n            ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER_INSTANCE_NAMES));\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                instanceNames.add(rs.getString(COL_INSTANCE_NAME));\n            }\n\n            return instanceNames;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n    \n    /**\n     * <p>\n     * Delete a fired trigger.\n     * </p>\n     * \n     * @param conn\n     *          the DB Connection\n     * @param entryId\n     *          the fired trigger entry to delete\n     * @return the number of rows deleted\n     */\n    public int deleteFiredTrigger(Connection conn, String entryId)\n        throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_FIRED_TRIGGER));\n            ps.setString(1, entryId);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int selectJobExecutionCount(Connection conn, JobKey jobKey) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_JOB_EXECUTION_COUNT));\n            ps.setString(1, jobKey.getName());\n            ps.setString(2, jobKey.getGroup());\n\n            rs = ps.executeQuery();\n\n            return (rs.next()) ? rs.getInt(1) : 0;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n    \n    public int insertSchedulerState(Connection conn, String theInstanceId,\n            long checkInTime, long interval)\n        throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_SCHEDULER_STATE));\n            ps.setString(1, theInstanceId);\n            ps.setLong(2, checkInTime);\n            ps.setLong(3, interval);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int deleteSchedulerState(Connection conn, String theInstanceId)\n        throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(DELETE_SCHEDULER_STATE));\n            ps.setString(1, theInstanceId);\n\n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n\n    public int updateSchedulerState(Connection conn, String theInstanceId, long checkInTime)\n        throws SQLException {\n        PreparedStatement ps = null;\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_SCHEDULER_STATE));\n            ps.setLong(1, checkInTime);\n            ps.setString(2, theInstanceId);\n        \n            return ps.executeUpdate();\n        } finally {\n            closeStatement(ps);\n        }\n    }\n        \n    public List<SchedulerStateRecord> selectSchedulerStateRecords(Connection conn, String theInstanceId)\n        throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        try {\n            List<SchedulerStateRecord> lst = new LinkedList<>();\n\n            if (theInstanceId != null) {\n                ps = conn.prepareStatement(rtp(SELECT_SCHEDULER_STATE));\n                ps.setString(1, theInstanceId);\n            } else {\n                ps = conn.prepareStatement(rtp(SELECT_SCHEDULER_STATES));\n            }\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                SchedulerStateRecord rec = new SchedulerStateRecord();\n\n                rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME));\n                rec.setCheckinTimestamp(rs.getLong(COL_LAST_CHECKIN_TIME));\n                rec.setCheckinInterval(rs.getLong(COL_CHECKIN_INTERVAL));\n\n                lst.add(rec);\n            }\n\n            return lst;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * Replace the table prefix in a query by replacing any occurrences of\n     * \"{0}\" with the table prefix.\n     * </p>\n     * \n     * @param query\n     *          the unsubstituted query\n     * @return the query, with proper table prefix substituted\n     */\n    protected final String rtp(String query) {\n        return Util.rtp(query, tablePrefix, getSchedulerNameLiteral());\n    }\n\n    private String schedNameLiteral = null;\n    protected String getSchedulerNameLiteral() {\n        if(schedNameLiteral == null)\n            schedNameLiteral = \"'\" + schedName + \"'\";\n        return schedNameLiteral;\n    }\n\n    /**\n     * <p>\n     * Create a serialized <code>java.util.ByteArrayOutputStream</code>\n     * version of an Object.\n     * </p>\n     * \n     * @param obj\n     *          the object to serialize\n     * @return the serialized ByteArrayOutputStream\n     * @throws IOException\n     *           if serialization causes an error\n     */\n    protected ByteArrayOutputStream serializeObject(Object obj)\n        throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        if (null != obj) {\n            ObjectOutputStream out = new ObjectOutputStream(baos);\n            out.writeObject(obj);\n            out.flush();\n        }\n        return baos;\n    }\n\n    /**\n     * <p>\n     * Remove the transient data from and then create a serialized <code>java.util.ByteArrayOutputStream</code>\n     * version of a <code>{@link org.quartz.JobDataMap}</code>.\n     * </p>\n     * \n     * @param data\n     *          the JobDataMap to serialize\n     * @return the serialized ByteArrayOutputStream\n     * @throws IOException\n     *           if serialization causes an error\n     */\n    protected ByteArrayOutputStream serializeJobData(JobDataMap data)\n        throws IOException {\n        if (canUseProperties()) {\n            return serializeProperties(data);\n        }\n\n        try {\n            return serializeObject(data);\n        } catch (NotSerializableException e) {\n            throw new NotSerializableException(\n                \"Unable to serialize JobDataMap for insertion into \" + \n                \"database because the value of property '\" + \n                getKeyOfNonSerializableValue(data) + \n                \"' is not serializable: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Find the key of the first non-serializable value in the given Map.\n     * \n     * @return The key of the first non-serializable value in the given Map or \n     * null if all values are serializable.\n     */\n    protected Object getKeyOfNonSerializableValue(Map<?, ?> data) {\n        for (Map.Entry<?, ?> value : data.entrySet()) {\n\n            try {\n                serializeObject(value.getValue()).close();\n            } catch (IOException e) {\n                return value.getKey();\n            }\n        }\n        \n        // As long as it is true that the Map was not serializable, we should\n        // not hit this case.\n        return null;   \n    }\n    \n    /**\n     * serialize the java.util.Properties\n     */\n    private ByteArrayOutputStream serializeProperties(JobDataMap data)\n        throws IOException {\n        ByteArrayOutputStream ba = new ByteArrayOutputStream();\n        if (null != data) {\n            Properties properties = convertToProperty(data.getWrappedMap());\n            properties.store(ba, \"\");\n        }\n\n        return ba;\n    }\n\n    /**\n     * convert the JobDataMap into a list of properties\n     */\n    protected Map<?, ?> convertFromProperty(Properties properties) {\n        return new HashMap<>(properties);\n    }\n\n    /**\n     * convert the JobDataMap into a list of properties\n     */\n    protected Properties convertToProperty(Map<?, ?> data) throws IOException {\n        Properties properties = new Properties();\n\n        for (Map.Entry<?, ?> value : data.entrySet()) {\n\n            Object key = value.getKey();\n            Object val = (value.getValue() == null) ? \"\" : value.getValue();\n\n            if (!(key instanceof String)) {\n                throw new IOException(\"JobDataMap keys/values must be Strings \"\n                        + \"when the 'useProperties' property is set. \"\n                        + \" offending Key: \" + key);\n            }\n\n            if (!(val instanceof String)) {\n                throw new IOException(\"JobDataMap values must be Strings \"\n                        + \"when the 'useProperties' property is set. \"\n                        + \" Key of offending value: \" + key);\n            }\n\n            properties.put(key, val);\n        }\n        \n        return properties;\n    }\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        Object obj = null;\n\n        Blob blobLocator = rs.getBlob(colName);\n        if (blobLocator != null && blobLocator.length() != 0) {\n            InputStream binaryInput = blobLocator.getBinaryStream();\n\n            if (null != binaryInput) {\n                if (binaryInput instanceof ByteArrayInputStream\n                    && ((ByteArrayInputStream) binaryInput).available() == 0 ) {\n                    //do nothing\n                } else {\n                    try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                        obj = in.readObject();\n                    }\n                }\n            }\n\n        }\n        return obj;\n    }\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs for job details. The default implementation\n     * uses standard JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            Blob blobLocator = rs.getBlob(colName);\n            if (blobLocator != null) {\n                return blobLocator.getBinaryStream();\n            } else {\n                return null;\n            }\n        }\n\n        return getObjectFromBlob(rs, colName);\n    }\n\n    /** \n     * @see org.quartz.impl.jdbcjobstore.DriverDelegate#selectPausedTriggerGroups(java.sql.Connection)\n     */\n    public Set<String> selectPausedTriggerGroups(Connection conn) throws SQLException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        HashSet<String> set = new HashSet<>();\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_PAUSED_TRIGGER_GROUPS));\n            rs = ps.executeQuery();\n\n            while (rs.next()) {\n                String groupName = rs.getString(COL_TRIGGER_GROUP);\n                set.add(groupName);\n            }\n            return set;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n    }\n\n    /**\n     * Cleanup helper method that closes the given <code>ResultSet</code>\n     * while ignoring any errors.\n     */\n    protected static void closeResultSet(ResultSet rs) {\n        if (null != rs) {\n            try {\n                rs.close();\n            } catch (SQLException ignore) {\n            }\n        }\n    }\n\n    /**\n     * Cleanup helper method that closes the given <code>Statement</code>\n     * while ignoring any errors.\n     */\n    protected static void closeStatement(Statement statement) {\n        if (null != statement) {\n            try {\n                statement.close();\n            } catch (SQLException ignore) {\n            }\n        }\n    }\n    \n\n    /**\n     * Sets the designated parameter to the given Java <code>boolean</code> value.\n     * This just wraps <code>{@link PreparedStatement#setBoolean(int, boolean)}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support the boolean type.\n     */\n    protected void setBoolean(PreparedStatement ps, int index, boolean val) throws SQLException {\n        ps.setBoolean(index, val);\n    }\n\n    /**\n     * Retrieves the value of the designated column in the current row as\n     * a <code>boolean</code>.\n     * This just wraps <code>{@link ResultSet#getBoolean(java.lang.String)}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support the boolean type.\n     */\n    protected boolean getBoolean(ResultSet rs, String columnName) throws SQLException {\n        return rs.getBoolean(columnName);\n    }\n    \n    /**\n     * Retrieves the value of the designated column index in the current row as\n     * a <code>boolean</code>.\n     * This just wraps <code>{@link ResultSet#getBoolean(java.lang.String)}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support the boolean type.\n     */\n    protected boolean getBoolean(ResultSet rs, int columnIndex) throws SQLException {\n        return rs.getBoolean(columnIndex);\n    }\n    \n    /**\n     * Sets the designated parameter to the byte array of the given\n     * <code>ByteArrayOutputStream</code>.  Will set parameter value to null if the \n     * <code>ByteArrayOutputStream</code> is null.\n     * This just wraps <code>{@link PreparedStatement#setBytes(int, byte[])}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support storing bytes in this way.\n     */\n    protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException {\n        ps.setBytes(index, (baos == null) ? new byte[0] : baos.toByteArray());\n    }\n\n    @Override\n    public boolean isUsingEnhancedStatements() {\n        return this.useEnhancedStatements;\n    }\n\n    @Override\n    public void setUseEnhancedStatements(boolean useEnhancedStatements) {\n        this.useEnhancedStatements = useEnhancedStatements;\n    }\n    @FunctionalInterface\n    protected interface PreparedStatementConsumer {\n        void accept(PreparedStatement ps) throws SQLException;\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/StdRowLockSemaphore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * Internal database based lock handler for providing thread/resource locking \n * in order to protect resources from being altered by multiple threads at the \n * same time.\n * \n * @author jhouse\n */\npublic class StdRowLockSemaphore extends DBSemaphore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String SELECT_FOR_LOCK = \"SELECT * FROM \"\n            + TABLE_PREFIX_SUBST + TABLE_LOCKS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_LOCK_NAME + \" = ? FOR UPDATE\";\n\n    public static final String INSERT_LOCK = \"INSERT INTO \"\n        + TABLE_PREFIX_SUBST + TABLE_LOCKS + \"(\" + COL_SCHEDULER_NAME + \", \" + COL_LOCK_NAME + \") VALUES (\" \n        + SCHED_NAME_SUBST + \", ?)\"; \n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public StdRowLockSemaphore() {\n        super(DEFAULT_TABLE_PREFIX, null, SELECT_FOR_LOCK, INSERT_LOCK);\n    }\n\n    public StdRowLockSemaphore(String tablePrefix, String schedName, String selectWithLockSQL) {\n        super(tablePrefix, schedName, selectWithLockSQL != null ? selectWithLockSQL : SELECT_FOR_LOCK, INSERT_LOCK);\n    }\n\n    // Data Members\n\n    // Configurable lock retry parameters\n    private int maxRetry = 3;\n    private long retryPeriod = 1000L;\n\n    public void setMaxRetry(int maxRetry) {\n        this.maxRetry = maxRetry;\n    }\n\n    public void setRetryPeriod(long retryPeriod) {\n        this.retryPeriod = retryPeriod;\n    }\n\n    public int getMaxRetry() {\n        return maxRetry;\n    }\n\n    public long getRetryPeriod() {\n        return retryPeriod;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Execute the SQL select for update that will lock the proper database row.\n     */\n    @Override\n    protected void executeSQL(Connection conn, final String lockName, final String expandedSQL, final String expandedInsertSQL) throws LockException {\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        SQLException initCause = null;\n        \n        // attempt lock two times (to work-around possible race conditions in inserting the lock row the first time running)\n        int count = 0;\n\n        // Configurable lock retry attempts\n        int maxRetryLocal = this.maxRetry;\n        long retryPeriodLocal = this.retryPeriod;\n\n        do {\n            count++;\n            try {\n                ps = conn.prepareStatement(expandedSQL);\n                ps.setString(1, lockName);\n                \n                if (getLog().isDebugEnabled()) {\n                    getLog().debug(\"Lock '{}' is being obtained: {}\", lockName, Thread.currentThread().getName());\n                }\n                rs = ps.executeQuery();\n                if (!rs.next()) {\n                    getLog().debug(\"Inserting new lock row for lock: '{}' being obtained by thread: {}\", lockName, Thread.currentThread().getName());\n                    rs.close();\n                    rs = null;\n                    ps.close();\n                    ps = null;\n                    ps = conn.prepareStatement(expandedInsertSQL);\n                    ps.setString(1, lockName);\n    \n                    int res = ps.executeUpdate();\n                    \n                    if(res != 1) {\n                        if(count < maxRetryLocal) {\n                            // pause a bit to give another thread some time to commit the insert of the new lock row\n                            try {\n                                Thread.sleep(retryPeriodLocal);\n                            } catch (InterruptedException ignore) {\n                                Thread.currentThread().interrupt();\n                            }\n                            // try again ...\n                            continue;\n                        }\n                    \n                        throw new SQLException(Util.rtp(\n                            \"No row exists, and one could not be inserted in table \" + TABLE_PREFIX_SUBST + TABLE_LOCKS + \n                            \" for lock named: \" + lockName, getTablePrefix(), getSchedulerNameLiteral()));\n                    }\n                }\n                \n                return; // obtained lock, go\n            } catch (SQLException sqle) {\n                //Exception src =\n                // (Exception)getThreadLocksObtainer().get(lockName);\n                //if(src != null)\n                //  src.printStackTrace();\n                //else\n                //  System.err.println(\"--- ***************** NO OBTAINER!\");\n    \n                if(initCause == null)\n                    initCause = sqle;\n                \n                if (getLog().isDebugEnabled()) {\n                    getLog().debug(\"Lock '{}' was not obtained by: {}{}\", lockName, Thread.currentThread().getName(), count < maxRetryLocal ? \" - will try again.\" : \"\");\n                }\n                \n                if(count < maxRetryLocal) {\n                    try {\n                        conn.rollback();\n                    } catch (SQLException e) {\n                        getLog().error(\"Couldn't rollback jdbc connection. {}\", e.getMessage(), e);\n                    }\n                    // pause a bit to give another thread some time to commit the insert of the new lock row\n                    try {\n                        Thread.sleep(retryPeriodLocal);\n                    } catch (InterruptedException ignore) {\n                        Thread.currentThread().interrupt();\n                    }\n                    // try again ...\n                    continue;\n                }\n                \n                throw new LockException(\"Failure obtaining db row lock: \"\n                        + sqle.getMessage(), sqle);\n            } finally {\n                if (rs != null) { \n                    try {\n                        rs.close();\n                    } catch (Exception ignore) {\n                    }\n                }\n                if (ps != null) {\n                    try {\n                        ps.close();\n                    } catch (Exception ignore) {\n                    }\n                }\n            }\n        } while(count < (maxRetryLocal + 1));\n        \n        throw new LockException(\"Failure obtaining db row lock, reached maximum number of attempts. Initial exception (if any) attached as root cause.\", initCause);\n    }\n\n    protected String getSelectWithLockSQL() {\n        return getSQL();\n    }\n\n    public void setSelectWithLockSQL(String selectWithLockSQL) {\n        setSQL(selectWithLockSQL);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/SybaseDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for the Sybase database.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n * @author jhouse\n * @author Ray Case\n */\npublic class SybaseDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override           \n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        InputStream binaryInput = rs.getBinaryStream(colName);\n\n        if(binaryInput == null || binaryInput.available() == 0) {\n            return null;\n        }\n\n        Object obj;\n\n        try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n            obj = in.readObject();\n        }\n\n        return obj;\n    }\n\n    @Override           \n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        if (canUseProperties()) {\n            return rs.getBinaryStream(colName);\n        }\n        return getObjectFromBlob(rs, colName);\n    }\n    \n    /**\n     * Sets the designated parameter to the byte array of the given\n     * <code>ByteArrayOutputStream</code>. Will set parameter value to null if the\n     * <code>ByteArrayOutputStream</code> is null.\n     * This just wraps <code>{@link PreparedStatement#setBytes(int, byte[])}</code>\n     * by default, but it can be overloaded by subclass delegates for databases that\n     * don't explicitly support storing bytes in this way.\n     */\n    @Override\n    protected void setBytes(PreparedStatement ps, int index, ByteArrayOutputStream baos) throws SQLException {\n        ps.setBytes(index, (baos == null) ? null: baos.toByteArray());\n    } \n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/TablePrefixAware.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\n/**\n * Interface for Quartz objects that need to know what the table prefix of\n * the tables used by a JDBC JobStore is.\n */\npublic interface TablePrefixAware {\n    void setTablePrefix(String tablePrefix);\n    void setSchedName(String schedName);\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/TriggerPersistenceDelegate.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.JobDetail;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * An interface which provides an implementation for storing a particular\n * type of <code>Trigger</code>'s extended properties.\n *  \n * @author jhouse\n */\npublic interface TriggerPersistenceDelegate {\n\n    void initialize(String tablePrefix, String schedulerName);\n    \n    boolean canHandleTriggerType(OperableTrigger trigger);\n    \n    String getHandledTriggerTypeDiscriminator();\n    \n    int insertExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException;\n\n    int updateExtendedTriggerProperties(Connection conn, OperableTrigger trigger, String state, JobDetail jobDetail) throws SQLException, IOException;\n    \n    int deleteExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException;\n\n    TriggerPropertyBundle loadExtendedTriggerProperties(Connection conn, TriggerKey triggerKey) throws SQLException;\n\n    default TriggerPropertyBundle loadExtendedTriggerPropertiesFromResultSet(ResultSet resultSet, TriggerKey triggerKey) throws SQLException {\n        throw new UnsupportedOperationException(\"This delegate does not support loading from ResultSet\");\n    }\n\n    default boolean hasInlinedResultSetProperties() {\n        return false;\n    }\n\n    class TriggerPropertyBundle {\n        \n        private final ScheduleBuilder<?> sb;\n        private final String[] statePropertyNames;\n        private final Object[] statePropertyValues;\n        \n        public TriggerPropertyBundle(ScheduleBuilder<?> sb, String[] statePropertyNames, Object[] statePropertyValues) {\n            this.sb = sb;\n            this.statePropertyNames = statePropertyNames;\n            this.statePropertyValues = statePropertyValues;\n        }\n\n        public ScheduleBuilder<?> getScheduleBuilder() {\n            return sb;\n        }\n\n        public String[] getStatePropertyNames() {\n            return statePropertyNames;\n        }\n\n        public Object[] getStatePropertyValues() {\n            return statePropertyValues;\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/TriggerStatus.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.util.Date;\n\nimport org.quartz.JobKey;\nimport org.quartz.TriggerKey;\n\n\n/**\n * <p>\n * Object representing a job or trigger key.\n * </p>\n * \n * @author James House\n */\npublic class TriggerStatus {\n\n    // FUTURE_TODO: Repackage under spi or root pkg ?, put status constants here.\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private TriggerKey key;\n\n    private JobKey jobKey;\n\n    private final String status;\n    \n    private final Date nextFireTime;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Construct a new TriggerStatus with the status name and nextFireTime.\n     * \n     * @param status\n     *          the trigger's status\n     * @param nextFireTime\n     *          the next time the trigger will fire\n     */\n    public TriggerStatus(String status, Date nextFireTime) {\n        this.status = status;\n        this.nextFireTime = nextFireTime;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public JobKey getJobKey() {\n        return jobKey;\n    }\n\n    public void setJobKey(JobKey jobKey) {\n        this.jobKey = jobKey;\n    }\n\n    public TriggerKey getKey() {\n        return key;\n    }\n\n    public void setKey(TriggerKey key) {\n        this.key = key;\n    }\n\n    /**\n     * <p>\n     * Get the name portion of the key.\n     * </p>\n     * \n     * @return the name\n     */\n    public String getStatus() {\n        return status;\n    }\n\n    /**\n     * <p>\n     * Get the group portion of the key.\n     * </p>\n     * \n     * @return the group\n     */\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Return the string representation of the TriggerStatus.\n     * </p>\n     *  \n     */\n    @Override\n    public String toString() {\n        return \"status: \" + getStatus() + \", next Fire = \" + getNextFireTime();\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/UpdateLockRowSemaphore.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n/**\n * Provide thread/resource locking in order to protect\n * resources from being altered by multiple threads at the same time using\n * a db row update.\n * \n * <p>\n * <b>Note:</b> This Semaphore implementation is useful for databases that do\n * not support row locking via \"SELECT FOR UPDATE\" type syntax, for example\n * Microsoft SQLServer (MSSQL).\n * </p> \n */\npublic class UpdateLockRowSemaphore extends DBSemaphore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constants.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String UPDATE_FOR_LOCK = \n        \"UPDATE \" + TABLE_PREFIX_SUBST + TABLE_LOCKS + \n        \" SET \" + COL_LOCK_NAME + \" = \" + COL_LOCK_NAME +\n        \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_LOCK_NAME + \" = ? \";\n\n\n    public static final String INSERT_LOCK = \"INSERT INTO \"\n        + TABLE_PREFIX_SUBST + TABLE_LOCKS + \"(\" + COL_SCHEDULER_NAME + \", \" + COL_LOCK_NAME + \") VALUES (\" \n        + SCHED_NAME_SUBST + \", ?)\"; \n    \n    private static final int RETRY_COUNT = 2;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public UpdateLockRowSemaphore() {\n        super(DEFAULT_TABLE_PREFIX, null, UPDATE_FOR_LOCK, INSERT_LOCK);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Execute the SQL select for update that will lock the proper database row.\n     */\n    @Override\n    protected void executeSQL(Connection conn, final String lockName, final String expandedSQL, final String expandedInsertSQL) throws LockException {\n        SQLException lastFailure = null;\n        for (int i = 0; i < RETRY_COUNT; i++) {\n            try {\n                if (!lockViaUpdate(conn, lockName, expandedSQL)) {\n                    lockViaInsert(conn, lockName, expandedInsertSQL);\n                }\n                return;\n            } catch (SQLException e) {\n                lastFailure = e;\n                if ((i + 1) == RETRY_COUNT) {\n                    getLog().debug(\"Lock '{}' was not obtained by: {}\", lockName, Thread.currentThread().getName());\n                } else {\n                    getLog().debug(\"Lock '{}' was not obtained by: {} - will try again.\", lockName, Thread.currentThread().getName());\n                }\n                try {\n                    Thread.sleep(1000L);\n                } catch (InterruptedException ie) {\n                    Thread.currentThread().interrupt();\n                }\n            }\n        }\n        throw new LockException(\"Failure obtaining db row lock: \" + lastFailure.getMessage(), lastFailure);\n    }\n    \n    protected String getUpdateLockRowSQL() {\n        return getSQL();\n    }\n\n    public void setUpdateLockRowSQL(String updateLockRowSQL) {\n        setSQL(updateLockRowSQL);\n    }\n\n    private boolean lockViaUpdate(Connection conn, String lockName, String sql) throws SQLException {\n        try (PreparedStatement ps = conn.prepareStatement(sql)) {\n            ps.setString(1, lockName);\n            getLog().debug(\"Lock '{}' is being obtained: {}\", lockName, Thread.currentThread().getName());\n            return ps.executeUpdate() >= 1;\n        }\n    }\n\n    private void lockViaInsert(Connection conn, String lockName, String sql) throws SQLException {\n        getLog().debug(\"Inserting new lock row for lock: '{}' being obtained by thread: {}\", lockName, Thread.currentThread().getName());\n        try (PreparedStatement ps = conn.prepareStatement(sql)) {\n            ps.setString(1, lockName);\n            if (ps.executeUpdate() != 1) {\n                throw new SQLException(Util.rtp(\n                        \"No row exists, and one could not be inserted in table \" + TABLE_PREFIX_SUBST + TABLE_LOCKS +\n                                \" for lock named: \" + lockName, getTablePrefix(), getSchedulerNameLiteral()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/Util.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.JobPersistenceException;\n\nimport java.beans.BeanInfo;\nimport java.beans.Introspector;\nimport java.beans.PropertyDescriptor;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.text.MessageFormat;\nimport java.util.Arrays;\nimport java.util.Locale;\n\n/**\n * <p>\n * This class contains utility functions for use in all delegate classes.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic final class Util {\n\n    /**\n     * Private constructor because this is a pure utility class.\n     */\n    private Util() {\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Replace the table prefix in a query by replacing any occurrences of\n     * \"{0}\" with the table prefix.\n     * </p>\n     * \n     * @param query\n     *          the unsubstituted query\n     * @param tablePrefix\n     *          the table prefix\n     * @return the query, with proper table prefix substituted\n     */\n    public static String rtp(String query, String tablePrefix, String schedNameLiteral) {\n        return MessageFormat.format(query, new Object[]{tablePrefix, schedNameLiteral});\n    }\n\n    /**\n     * <p>\n     * Obtain a unique key for a given job.\n     * </p>\n     * \n     * @param jobName\n     *          the job name\n     * @param groupName\n     *          the group containing the job\n     * @return a unique <code>String</code> key\n     */\n    static String getJobNameKey(String jobName, String groupName) {\n        return (groupName + \"_$x$x$_\" + jobName).intern();\n    }\n\n    /**\n     * <p>\n     * Obtain a unique key for a given trigger.\n     * </p>\n     * \n     * @param triggerName\n     *          the trigger name\n     * @param groupName\n     *          the group containing the trigger\n     * @return a unique <code>String</code> key\n     */\n    static String getTriggerNameKey(String triggerName, String groupName) {\n        return (groupName + \"_$x$x$_\" + triggerName).intern();\n    }\n    \n    /**\n     * Cleanup helper method that closes the given <code>ResultSet</code>\n     * while ignoring any errors.\n     */\n    public static void closeResultSet(ResultSet rs) {\n        if (null != rs) {\n            try {\n                rs.close();\n            } catch (SQLException ignore) {\n            }\n        }\n    }\n\n    /**\n     * Cleanup helper method that closes the given <code>Statement</code>\n     * while ignoring any errors.\n     */\n    public static void closeStatement(Statement statement) {\n        if (null != statement) {\n            try {\n                statement.close();\n            } catch (SQLException ignore) {\n            }\n        }\n    }\n    \n    \n    public static void setBeanProps(Object obj, String[] propNames, Object[] propValues)  throws JobPersistenceException {\n        \n        if(propNames == null || propNames.length == 0)\n            return;\n        if(propNames.length != propValues.length)\n            throw new IllegalArgumentException(\"propNames[].length != propValues[].length\");\n        \n        String name = null;\n        \n        try {\n            BeanInfo bi = Introspector.getBeanInfo(obj.getClass());\n            PropertyDescriptor[] propDescs = bi.getPropertyDescriptors();\n        \n            for(int i=0; i < propNames.length; i++) {\n                name = propNames[i];\n                String c = name.substring(0, 1).toUpperCase(Locale.US);\n                String methName = \"set\" + c + name.substring(1);\n        \n                java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs);\n        \n                if (setMeth == null) {\n                    throw new NoSuchMethodException(\n                            \"No setter for property '\" + name + \"'\");\n                }\n    \n                Class<?>[] params = setMeth.getParameterTypes();\n                if (params.length != 1) {\n                    throw new NoSuchMethodException(\n                        \"No 1-argument setter for property '\" + name + \"'\");\n                }\n                \n                setMeth.invoke(obj, new Object[]{ propValues[i] });\n            }\n        }\n        catch(Exception e) {\n            throw new JobPersistenceException(\n                \"Unable to set property named: \" + name +\" of object of type: \" + obj.getClass().getCanonicalName(), \n                e); \n        }\n    }\n\n    private static java.lang.reflect.Method getSetMethod(String name, PropertyDescriptor[] props) {\n        for (PropertyDescriptor prop : props) {\n            java.lang.reflect.Method wMeth = prop.getWriteMethod();\n\n            if (wMeth != null && wMeth.getName().equals(name)) {\n                return wMeth;\n            }\n        }\n    \n        return null;\n    }\n\n    static boolean containsColumnNames(ResultSet rs, String... colNames) throws SQLException {\n        ResultSetMetaData rsmd = rs.getMetaData();\n        int columnCount = rsmd.getColumnCount();\n\n        for (int i = 1; i <= columnCount; i++ ) {\n            String name = rsmd.getColumnName(i);\n            for (String colName : colNames) {\n                if (colName.equalsIgnoreCase(name)) {\n                    return true;\n                }\n            }\n            // Do stuff with name\n        }\n        return false;\n    }\n\n    static String getString(ResultSet resultSet, String... columnNames) throws SQLException {\n        for (String columnName : columnNames) {\n            if (containsColumnNames(resultSet, columnName)) {\n                return resultSet.getString(columnName);\n            }\n        }\n        throw new SQLException(\"Missing columns in result set: \" + Arrays.toString(columnNames));\n    }\n\n    static boolean getBoolean(ResultSet resultSet, String... columnNames) throws SQLException {\n        for (String columnName : columnNames) {\n            if (containsColumnNames(resultSet, columnName)) {\n                return resultSet.getBoolean(columnName);\n            }\n        }\n        throw new SQLException(\"Missing columns in result set: \" + Arrays.toString(columnNames));\n    }\n\n    /**\n     * Checks if all columns are null in the result set.\n     * @param resultSet the result set\n     * @param columnNames columns names to check\n     * @return true if all columns are null, false otherwise\n     * @throws SQLException\n     */\n    static boolean areNull(ResultSet resultSet, String... columnNames) throws SQLException {\n        //TODO: check if resultSet is closed?\n        for (String columnName : columnNames) {\n            if (containsColumnNames(resultSet, columnName)) {\n                if (resultSet.getObject(columnName) != null) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/WebLogicDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.sql.Blob;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * This is a driver delegate for the WebLogic JDBC driver.\n * </p>\n * \n * @see org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate\n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class WebLogicDelegate extends StdJDBCDelegate {\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    /**\n     * <p>\n     * This method should be overridden by any delegate subclasses that need\n     * special handling for BLOBs. The default implementation uses standard\n     * JDBC <code>java.sql.Blob</code> operations.\n     * </p>\n     * \n     * @param rs\n     *          the result set, already queued to the correct row\n     * @param colName\n     *          the column name for the BLOB\n     * @return the deserialized Object from the ResultSet BLOB\n     * @throws ClassNotFoundException\n     *           if a class found during deserialization cannot be found\n     * @throws IOException\n     *           if deserialization causes an error\n     */\n    @Override\n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        \n        Object obj = null;\n\n        Blob blobLocator = rs.getBlob(colName);\n        InputStream binaryInput = null;\n        try {\n            if (null != blobLocator && blobLocator.length() > 0) {\n                binaryInput = blobLocator.getBinaryStream();\n            }\n        } catch (Exception ignore) {\n        }\n\n        if (null != binaryInput) {\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n        }\n\n        return obj;\n    }\n\n    @Override\n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        \n        if (canUseProperties()) {\n            Blob blobLocator = rs.getBlob(colName);\n            InputStream binaryInput = null;\n            try {\n                if (null != blobLocator && blobLocator.length() > 0) {\n                    binaryInput = blobLocator.getBinaryStream();\n                }\n            } catch (Exception ignore) {\n            }\n            return binaryInput;\n        }\n\n        return getObjectFromBlob(rs, colName);\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/oracle/OracleDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore.oracle;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.math.BigDecimal;\nimport java.sql.Blob;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDetail;\nimport org.quartz.impl.jdbcjobstore.StdJDBCDelegate;\nimport org.quartz.impl.jdbcjobstore.TriggerPersistenceDelegate;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * <p>\n * This is a driver delegate for the Oracle 10 and 11 database.\n * </p>\n * \n * @see org.quartz.impl.jdbcjobstore.WebLogicDelegate\n * @see org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate\n * @author James House\n * @author Patrick Lightbody\n * @author Eric Mueller\n */\npublic class OracleDelegate extends StdJDBCDelegate {\n\n    public static final String INSERT_ORACLE_JOB_DETAIL = \"INSERT INTO \"\n        + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" (\" + COL_SCHEDULER_NAME + \", \" \n        + COL_JOB_NAME + \", \" + COL_JOB_GROUP + \", \" + COL_DESCRIPTION + \", \"\n        + COL_JOB_CLASS + \", \" + COL_IS_DURABLE + \", \" \n        + COL_IS_NONCONCURRENT +  \", \" + COL_IS_UPDATE_DATA + \", \" \n        + COL_REQUESTS_RECOVERY + \", \"\n        + COL_JOB_DATAMAP + \") \" + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, ?, ?, ?, ?, ?, ?, ?, EMPTY_BLOB())\";\n\n    public static final String UPDATE_ORACLE_JOB_DETAIL = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" SET \"\n            + COL_DESCRIPTION + \" = ?, \" + COL_JOB_CLASS + \" = ?, \"\n            + COL_IS_DURABLE + \" = ?, \" + COL_IS_NONCONCURRENT + \" = ?, \"  \n            + COL_IS_UPDATE_DATA + \" = ?, \" + COL_REQUESTS_RECOVERY + \" = ?, \"\n            + COL_JOB_DATAMAP + \" = EMPTY_BLOB() \"\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    public static final String UPDATE_ORACLE_JOB_DETAIL_BLOB = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_JOB_DETAILS + \" SET \"\n            + COL_JOB_DATAMAP + \" = ? \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME\n            + \" = ? AND \" + COL_JOB_GROUP + \" = ?\";\n\n    public static final String SELECT_ORACLE_JOB_DETAIL_BLOB = \"SELECT \"\n            + COL_JOB_DATAMAP + \" FROM \" + TABLE_PREFIX_SUBST\n            + TABLE_JOB_DETAILS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_JOB_NAME + \" = ? AND \"\n            + COL_JOB_GROUP + \" = ? FOR UPDATE\";\n\n    public static final String UPDATE_ORACLE_TRIGGER = \"UPDATE \"  \n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \" + COL_JOB_NAME  \n        + \" = ?, \" + COL_JOB_GROUP + \" = ?, \"\n        + COL_DESCRIPTION + \" = ?, \" + COL_NEXT_FIRE_TIME + \" = ?, \"\n        + COL_PREV_FIRE_TIME + \" = ?, \" + COL_TRIGGER_STATE + \" = ?, \"\n        + COL_TRIGGER_TYPE + \" = ?, \" + COL_START_TIME + \" = ?, \"\n        + COL_END_TIME + \" = ?, \" + COL_CALENDAR_NAME + \" = ?, \"\n        + COL_MISFIRE_INSTRUCTION + \" = ?, \"\n        + COL_PRIORITY + \" = ? WHERE \" \n        + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    \n    public static final String SELECT_ORACLE_TRIGGER_JOB_DETAIL_BLOB = \"SELECT \"\n        + COL_JOB_DATAMAP + \" FROM \" + TABLE_PREFIX_SUBST\n        + TABLE_TRIGGERS + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME + \" = ? AND \"\n        + COL_TRIGGER_GROUP + \" = ? FOR UPDATE\";\n\n    public static final String UPDATE_ORACLE_TRIGGER_JOB_DETAIL_BLOB = \"UPDATE \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \"\n        + COL_JOB_DATAMAP + \" = ? \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME\n        + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n\n    public static final String UPDATE_ORACLE_TRIGGER_JOB_DETAIL_EMPTY_BLOB = \"UPDATE \"\n        + TABLE_PREFIX_SUBST + TABLE_TRIGGERS + \" SET \"\n        + COL_JOB_DATAMAP + \" = EMPTY_BLOB() \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n        + \" AND \" + COL_TRIGGER_NAME\n        + \" = ? AND \" + COL_TRIGGER_GROUP + \" = ?\";\n    \n    \n    public static final String INSERT_ORACLE_CALENDAR = \"INSERT INTO \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS + \" (\" + COL_SCHEDULER_NAME + \", \" \n            + COL_CALENDAR_NAME + \", \" + COL_CALENDAR + \") \" \n            + \" VALUES(\" + SCHED_NAME_SUBST + \", ?, EMPTY_BLOB())\";\n\n    public static final String SELECT_ORACLE_CALENDAR_BLOB = \"SELECT \"\n            + COL_CALENDAR + \" FROM \" + TABLE_PREFIX_SUBST + TABLE_CALENDARS\n            + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ? FOR UPDATE\";\n\n    public static final String UPDATE_ORACLE_CALENDAR_BLOB = \"UPDATE \"\n            + TABLE_PREFIX_SUBST + TABLE_CALENDARS + \" SET \" + COL_CALENDAR\n            + \" = ? \" + \" WHERE \" + COL_SCHEDULER_NAME + \" = \" + SCHED_NAME_SUBST\n            + \" AND \" + COL_CALENDAR_NAME + \" = ?\";\n\n    //---------------------------------------------------------------------------\n    // protected methods that can be overridden by subclasses\n    //---------------------------------------------------------------------------\n\n    @Override\n    protected Object getObjectFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        \n        Object obj = null;\n        InputStream binaryInput = rs.getBinaryStream(colName);\n        if (binaryInput != null) {\n            try (ObjectInputStream in = new ObjectInputStream(binaryInput)) {\n                obj = in.readObject();\n            }\n        }\n\n        return obj;\n    }\n\n    @Override\n    public int insertJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n\n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        byte[] data = baos.toByteArray();\n        PreparedStatement ps = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_ORACLE_JOB_DETAIL));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n            ps.setString(3, job.getDescription());\n            ps.setString(4, job.getJobClass().getName());\n            setBoolean(ps, 5, job.isDurable());\n            setBoolean(ps, 6, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 7, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 8, job.requestsRecovery());\n\n            ps.executeUpdate();\n            ps.close();\n\n            ps = conn.prepareStatement(rtp(SELECT_ORACLE_JOB_DETAIL_BLOB));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n\n            rs = ps.executeQuery();\n\n            int res = 0;\n\n            Blob dbBlob;\n            if (rs.next()) {\n                dbBlob = writeDataToBlob(rs, 1, data);\n            } else {\n                return res;\n            }\n\n            rs.close();\n            ps.close();\n\n            ps = conn.prepareStatement(rtp(UPDATE_ORACLE_JOB_DETAIL_BLOB));\n            ps.setBlob(1, dbBlob);\n            ps.setString(2, job.getKey().getName());\n            ps.setString(3, job.getKey().getGroup());\n\n            res = ps.executeUpdate();\n\n            return res;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n    }\n\n    @Override\n    protected Object getJobDataFromBlob(ResultSet rs, String colName)\n        throws ClassNotFoundException, IOException, SQLException {\n        \n        if (canUseProperties()) {\n            return rs.getBinaryStream(colName);\n        }\n\n        return getObjectFromBlob(rs, colName);\n    }\n\n    @Override\n    public int updateJobDetail(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        \n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        byte[] data = baos.toByteArray();\n\n        PreparedStatement ps = null;\n        PreparedStatement ps2 = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_ORACLE_JOB_DETAIL));\n            ps.setString(1, job.getDescription());\n            ps.setString(2, job.getJobClass().getName());\n            setBoolean(ps, 3, job.isDurable());\n            setBoolean(ps, 4, job.isConcurrentExecutionDisallowed());\n            setBoolean(ps, 5, job.isPersistJobDataAfterExecution());\n            setBoolean(ps, 6, job.requestsRecovery());\n            ps.setString(7, job.getKey().getName());\n            ps.setString(8, job.getKey().getGroup());\n\n            ps.executeUpdate();\n            ps.close();\n\n            ps = conn.prepareStatement(rtp(SELECT_ORACLE_JOB_DETAIL_BLOB));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n\n            rs = ps.executeQuery();\n\n            int res = 0;\n\n            if (rs.next()) {\n                Blob dbBlob = writeDataToBlob(rs, 1, data);\n                ps2 = conn.prepareStatement(rtp(UPDATE_ORACLE_JOB_DETAIL_BLOB));\n\n                ps2.setBlob(1, dbBlob);\n                ps2.setString(2, job.getKey().getName());\n                ps2.setString(3, job.getKey().getGroup());\n\n                res = ps2.executeUpdate();\n            }\n\n            return res;\n\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n            closeStatement(ps2);\n        }\n    }\n\n    @Override\n    public int insertTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        byte[] data = null;\n        if (!trigger.getJobDataMap().isEmpty()) {\n            data = serializeJobData(trigger.getJobDataMap()).toByteArray();\n        }\n        \n        PreparedStatement ps = null;\n        ResultSet rs = null;\n        \n        int insertResult;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_TRIGGER));\n            ps.setString(1, trigger.getKey().getName());\n            ps.setString(2, trigger.getKey().getGroup());\n            ps.setString(3, trigger.getJobKey().getName());\n            ps.setString(4, trigger.getJobKey().getGroup());\n            ps.setString(5, trigger.getDescription());\n            ps.setBigDecimal(6, new BigDecimal(String.valueOf(trigger\n                    .getNextFireTime().getTime())));\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(7, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(8, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n            ps.setString(9, type);\n            \n            ps.setBigDecimal(10, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(11, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(12, trigger.getCalendarName());\n            ps.setInt(13, trigger.getMisfireInstruction());\n            ps.setBinaryStream(14, null, 0);\n            ps.setInt(15, trigger.getPriority());\n\n            insertResult = ps.executeUpdate();\n\n            if(data != null) {\n                ps.close();\n\n                ps = conn\n                    .prepareStatement(rtp(UPDATE_ORACLE_TRIGGER_JOB_DETAIL_EMPTY_BLOB));\n                ps.setString(1, trigger.getKey().getName());\n                ps.setString(2, trigger.getKey().getGroup());\n                ps.executeUpdate();\n                ps.close();\n        \n                ps = conn.prepareStatement(rtp(SELECT_ORACLE_TRIGGER_JOB_DETAIL_BLOB));\n                ps.setString(1, trigger.getKey().getName());\n                ps.setString(2, trigger.getKey().getGroup());\n        \n                rs = ps.executeQuery();\n        \n                Blob dbBlob;\n                if (rs.next()) {\n                    dbBlob = writeDataToBlob(rs, 1, data);\n                } else {\n                    return 0;\n                }\n        \n                rs.close();\n                ps.close();\n        \n                ps = conn.prepareStatement(rtp(UPDATE_ORACLE_TRIGGER_JOB_DETAIL_BLOB));\n                ps.setBlob(1, dbBlob);\n                ps.setString(2, trigger.getKey().getName());\n                ps.setString(3, trigger.getKey().getGroup());\n        \n                ps.executeUpdate();\n            }\n\n            if(tDel == null)\n                insertBlobTrigger(conn, trigger);\n            else\n                tDel.insertExtendedTriggerProperties(conn, trigger, state, jobDetail);\n            \n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n        }\n\n        return insertResult;\n    }\n\n    @Override\n    public int updateTrigger(Connection conn, OperableTrigger trigger, String state,\n            JobDetail jobDetail) throws SQLException, IOException {\n\n        // save some clock cycles by unnecessarily writing job data blob ...\n        boolean updateJobData = trigger.getJobDataMap().isDirty();\n        byte[] data = null;\n        if (updateJobData && !trigger.getJobDataMap().isEmpty()) {\n            data = serializeJobData(trigger.getJobDataMap()).toByteArray();\n        }\n                \n        PreparedStatement ps = null;\n        PreparedStatement ps2 = null;\n        ResultSet rs = null;\n        \n        int insertResult;\n\n\n        try {\n            ps = conn.prepareStatement(rtp(UPDATE_ORACLE_TRIGGER));\n                \n            ps.setString(1, trigger.getJobKey().getName());\n            ps.setString(2, trigger.getJobKey().getGroup());\n            ps.setString(3, trigger.getDescription());\n            long nextFireTime = -1;\n            if (trigger.getNextFireTime() != null) {\n                nextFireTime = trigger.getNextFireTime().getTime();\n            }\n            ps.setBigDecimal(4, new BigDecimal(String.valueOf(nextFireTime)));\n            long prevFireTime = -1;\n            if (trigger.getPreviousFireTime() != null) {\n                prevFireTime = trigger.getPreviousFireTime().getTime();\n            }\n            ps.setBigDecimal(5, new BigDecimal(String.valueOf(prevFireTime)));\n            ps.setString(6, state);\n            \n            TriggerPersistenceDelegate tDel = findTriggerPersistenceDelegate(trigger);\n            \n            String type = TTYPE_BLOB;\n            if(tDel != null)\n                type = tDel.getHandledTriggerTypeDiscriminator();\n\n            ps.setString(7, type);\n            \n            ps.setBigDecimal(8, new BigDecimal(String.valueOf(trigger\n                    .getStartTime().getTime())));\n            long endTime = 0;\n            if (trigger.getEndTime() != null) {\n                endTime = trigger.getEndTime().getTime();\n            }\n            ps.setBigDecimal(9, new BigDecimal(String.valueOf(endTime)));\n            ps.setString(10, trigger.getCalendarName());\n            ps.setInt(11, trigger.getMisfireInstruction());\n            ps.setInt(12, trigger.getPriority());\n            ps.setString(13, trigger.getKey().getName());\n            ps.setString(14, trigger.getKey().getGroup());\n\n            insertResult = ps.executeUpdate();\n\n            if(updateJobData) {\n                ps.close();\n\n                ps = conn\n                        .prepareStatement(rtp(UPDATE_ORACLE_TRIGGER_JOB_DETAIL_EMPTY_BLOB));\n                ps.setString(1, trigger.getKey().getName());\n                ps.setString(2, trigger.getKey().getGroup());\n                ps.executeUpdate();\n                ps.close();\n\n                ps = conn.prepareStatement(rtp(SELECT_ORACLE_TRIGGER_JOB_DETAIL_BLOB));\n                ps.setString(1, trigger.getKey().getName());\n                ps.setString(2, trigger.getKey().getGroup());\n\n                rs = ps.executeQuery();\n\n                if (rs.next()) {\n                    Blob dbBlob = writeDataToBlob(rs, 1, data);\n                    ps2 = conn.prepareStatement(rtp(UPDATE_ORACLE_TRIGGER_JOB_DETAIL_BLOB));\n\n                    ps2.setBlob(1, dbBlob);\n                    ps2.setString(2, trigger.getKey().getName());\n                    ps2.setString(3, trigger.getKey().getGroup());\n\n                    ps2.executeUpdate();\n                }\n            }\n            \n            if(tDel == null)\n                updateBlobTrigger(conn, trigger);\n            else\n                tDel.updateExtendedTriggerProperties(conn, trigger, state, jobDetail);\n\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n            closeStatement(ps2);\n        }\n\n        return insertResult;\n    }\n    \n    @Override\n    public int insertCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeObject(calendar);\n\n        PreparedStatement ps = null;\n        PreparedStatement ps2 = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(INSERT_ORACLE_CALENDAR));\n            ps.setString(1, calendarName);\n\n            ps.executeUpdate();\n            ps.close();\n\n            ps = conn.prepareStatement(rtp(SELECT_ORACLE_CALENDAR_BLOB));\n            ps.setString(1, calendarName);\n\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                Blob dbBlob = writeDataToBlob(rs, 1, baos.toByteArray());\n                ps2 = conn.prepareStatement(rtp(UPDATE_ORACLE_CALENDAR_BLOB));\n\n                ps2.setBlob(1, dbBlob);\n                ps2.setString(2, calendarName);\n\n                return ps2.executeUpdate();\n            }\n\n            return 0;\n\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n            closeStatement(ps2);\n        }\n    }\n\n    @Override\n    public int updateCalendar(Connection conn, String calendarName,\n            Calendar calendar) throws IOException, SQLException {\n        ByteArrayOutputStream baos = serializeObject(calendar);\n\n        PreparedStatement ps = null;\n        PreparedStatement ps2 = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_ORACLE_CALENDAR_BLOB));\n            ps.setString(1, calendarName);\n\n            rs = ps.executeQuery();\n\n            if (rs.next()) {\n                Blob dbBlob = writeDataToBlob(rs, 1, baos.toByteArray());\n                ps2 = conn.prepareStatement(rtp(UPDATE_ORACLE_CALENDAR_BLOB));\n\n                ps2.setBlob(1, dbBlob);\n                ps2.setString(2, calendarName);\n\n                return ps2.executeUpdate();\n            }\n\n            return 0;\n\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n            closeStatement(ps2);\n        }\n    }\n\n    @Override\n    public int updateJobData(Connection conn, JobDetail job)\n        throws IOException, SQLException {\n        \n        ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap());\n        byte[] data = baos.toByteArray();\n\n        PreparedStatement ps = null;\n        PreparedStatement ps2 = null;\n        ResultSet rs = null;\n\n        try {\n            ps = conn.prepareStatement(rtp(SELECT_ORACLE_JOB_DETAIL_BLOB));\n            ps.setString(1, job.getKey().getName());\n            ps.setString(2, job.getKey().getGroup());\n\n            rs = ps.executeQuery();\n\n            int res = 0;\n\n            if (rs.next()) {\n                Blob dbBlob = writeDataToBlob(rs, 1, data);\n                ps2 = conn.prepareStatement(rtp(UPDATE_ORACLE_JOB_DETAIL_BLOB));\n\n                ps2.setBlob(1, dbBlob);\n                ps2.setString(2, job.getKey().getName());\n                ps2.setString(3, job.getKey().getGroup());\n\n                res = ps2.executeUpdate();\n            }\n\n            return res;\n        } finally {\n            closeResultSet(rs);\n            closeStatement(ps);\n            closeStatement(ps2);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    protected Blob writeDataToBlob(ResultSet rs, int column, byte[] data) throws SQLException {\n\n        Blob blob = rs.getBlob(column); // get blob\n\n        if (blob == null) { \n            throw new SQLException(\"Driver's Blob representation is null!\");\n        }\n        \n        if (blob instanceof oracle.sql.BLOB) { // is it an oracle blob?\n            ((oracle.sql.BLOB) blob).putBytes(1, data);\n            ((oracle.sql.BLOB) blob).trim(data.length);\n            return blob;\n        } else {\n            throw new SQLException(\n                    \"Driver's Blob representation is of an unsupported type: \"\n                            + blob.getClass().getName());\n        }\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/jdbcjobstore/oracle/weblogic/WebLogicOracleDelegate.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.jdbcjobstore.oracle.weblogic;\n\nimport org.quartz.impl.jdbcjobstore.oracle.OracleDelegate;\n\nimport java.lang.reflect.Method;\nimport java.sql.Blob;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * Handle Blobs correctly when Oracle is being used inside of Weblogic 8.1,\n * as discussed at: http://edocs.bea.com/wls/docs81/jdbc/thirdparty.html#1043705\n *  \n * @see org.quartz.impl.jdbcjobstore.WebLogicDelegate\n * @author James House\n * @author Igor Fedulov <a href=\"mailto:igor@fedulov.com\">igor@fedulov.com</a>\n */\npublic class WebLogicOracleDelegate extends OracleDelegate {\n\n    /**\n     * Check for the Weblogic Blob wrapper, and handle accordingly...\n     */\n    @Override\n    protected Blob writeDataToBlob(ResultSet rs, int column, byte[] data) throws SQLException {\n        Blob blob = rs.getBlob(column);\n        \n        if (blob == null) { \n            throw new SQLException(\"Driver's Blob representation is null!\");\n        }\n        \n        // handle thin driver's blob\n        if (blob instanceof weblogic.jdbc.vendor.oracle.OracleThinBlob) { \n            ((weblogic.jdbc.vendor.oracle.OracleThinBlob) blob).putBytes(1, data);\n            return blob;\n        } else if(blob.getClass().getPackage().getName().startsWith(\"weblogic.\")) {\n            // (more slowly) handle blob for wrappers of other variations of drivers...\n            try {\n                // try to find putBytes method...\n                Method m = blob.getClass().getMethod(\"putBytes\", new Class[] {long.class, byte[].class});\n                m.invoke(blob, new Object[] {1L, data});\n            } catch (Exception e) {\n                try {\n                    // Added this logic to the original code from OpenSymphony\n                    // putBytes method does not exist. Try setBytes\n                    Method m = blob.getClass().getMethod(\"setBytes\", new Class[] { long.class, byte[].class });\n                    m.invoke(blob, new Object[] {1L, data });\n                } catch (Exception e2) {\n                    throw new SQLException(\"Unable to find putBytes(long,byte[]) or setBytes(long,byte[]) methods on blob: \" + e2);\n                }\n            }\n            return blob;\n        } else {\n            return super.writeDataToBlob(rs, column, data);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/AndMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.Matcher;\nimport org.quartz.utils.Key;\n\n/**\n * Matches using an AND operator on two Matcher operands. \n *  \n * @author jhouse\n */\npublic class AndMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = 4697276220890670941L;\n\n    protected Matcher<T> leftOperand;\n    protected Matcher<T> rightOperand;\n    \n    protected AndMatcher(Matcher<T> leftOperand, Matcher<T> rightOperand) {\n        if(leftOperand == null || rightOperand == null)\n            throw new IllegalArgumentException(\"Two non-null operands required!\");\n        \n        this.leftOperand = leftOperand;\n        this.rightOperand = rightOperand;\n    }\n    \n    /**\n     * Create an AndMatcher that depends upon the result of both of the given matchers.\n     */\n    public static <U extends Key<?>> AndMatcher<U> and(Matcher<U> leftOperand, Matcher<U> rightOperand) {\n        return new AndMatcher<>(leftOperand, rightOperand);\n    }\n\n    public boolean isMatch(T key) {\n\n        return leftOperand.isMatch(key) && rightOperand.isMatch(key);\n    }\n\n    public Matcher<T> getLeftOperand() {\n        return leftOperand;\n    }\n\n    public Matcher<T> getRightOperand() {\n        return rightOperand;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result\n                + ((leftOperand == null) ? 0 : leftOperand.hashCode());\n        result = prime * result\n                + ((rightOperand == null) ? 0 : rightOperand.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        AndMatcher<?> other = (AndMatcher<?>) obj;\n        if (leftOperand == null) {\n            if (other.leftOperand != null)\n                return false;\n        } else if (!leftOperand.equals(other.leftOperand))\n            return false;\n        if (rightOperand == null) {\n            return other.rightOperand == null;\n        } else return rightOperand.equals(other.rightOperand);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/EverythingMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.JobKey;\nimport org.quartz.Matcher;\nimport org.quartz.TriggerKey;\nimport org.quartz.utils.Key;\n\n/**\n * Matches on the complete key being equal (both name and group). \n *  \n * @author jhouse\n */\npublic class EverythingMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = 202300056681974058L;\n    \n    protected EverythingMatcher() {\n    }\n    \n    /**\n     * Create an EverythingMatcher that matches all jobs.\n     */\n    public static EverythingMatcher<JobKey> allJobs() {\n        return new EverythingMatcher<>();\n    }\n\n    /**\n     * Create an EverythingMatcher that matches all triggers.\n     */\n    public static EverythingMatcher<TriggerKey> allTriggers() {\n        return new EverythingMatcher<>();\n    }\n    \n    public boolean isMatch(T key) {\n        return true;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if(obj == null)\n            return false;\n        \n        return obj.getClass().equals(getClass());\n    }\n\n    @Override\n    public int hashCode() {\n        return getClass().getName().hashCode();\n    }\n\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/GroupMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.JobKey;\nimport org.quartz.TriggerKey;\nimport org.quartz.utils.Key;\n\n/**\n * Matches on group (ignores name) property of Keys.\n *  \n * @author jhouse\n */\npublic class GroupMatcher<T extends Key<?>> extends StringMatcher<T> {\n  \n    private static final long serialVersionUID = -3275767650469343849L;\n\n    protected GroupMatcher(String compareTo, StringOperatorName compareWith) {\n        super(compareTo, compareWith);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches groups equaling the given string.\n     */\n    public static <T extends Key<T>> GroupMatcher<T> groupEquals(String compareTo) {\n        return new GroupMatcher<>(compareTo, StringOperatorName.EQUALS);\n    }\n\n    /**\n     * Create a GroupMatcher that matches job groups equaling the given string.\n     */\n    public static GroupMatcher<JobKey> jobGroupEquals(String compareTo) {\n        return GroupMatcher.groupEquals(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches trigger groups equaling the given string.\n     */\n    public static GroupMatcher<TriggerKey> triggerGroupEquals(String compareTo) {\n        return GroupMatcher.groupEquals(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches groups starting with the given string.\n     */\n    public static <T extends Key<T>> GroupMatcher<T> groupStartsWith(String compareTo) {\n        return new GroupMatcher<>(compareTo, StringOperatorName.STARTS_WITH);\n    }\n\n    /**\n     * Create a GroupMatcher that matches job groups starting with the given string.\n     */\n    public static GroupMatcher<JobKey> jobGroupStartsWith(String compareTo) {\n        return GroupMatcher.groupStartsWith(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches trigger groups starting with the given string.\n     */\n    public static GroupMatcher<TriggerKey> triggerGroupStartsWith(String compareTo) {\n        return GroupMatcher.groupStartsWith(compareTo);\n    }\n\n    /**\n     * Create a GroupMatcher that matches groups ending with the given string.\n     */\n    public static <T extends Key<T>> GroupMatcher<T> groupEndsWith(String compareTo) {\n        return new GroupMatcher<>(compareTo, StringOperatorName.ENDS_WITH);\n    }\n\n    /**\n     * Create a GroupMatcher that matches job groups ending with the given string.\n     */\n    public static GroupMatcher<JobKey> jobGroupEndsWith(String compareTo) {\n        return GroupMatcher.groupEndsWith(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches trigger groups ending with the given string.\n     */\n    public static GroupMatcher<TriggerKey> triggerGroupEndsWith(String compareTo) {\n        return GroupMatcher.groupEndsWith(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches groups containing the given string.\n     */\n    public static <T extends Key<T>> GroupMatcher<T> groupContains(String compareTo) {\n        return new GroupMatcher<>(compareTo, StringOperatorName.CONTAINS);\n    }\n\n    /**\n     * Create a GroupMatcher that matches job groups containing the given string.\n     */\n    public static GroupMatcher<JobKey> jobGroupContains(String compareTo) {\n        return GroupMatcher.groupContains(compareTo);\n    }\n    \n    /**\n     * Create a GroupMatcher that matches trigger groups containing the given string.\n     */\n    public static GroupMatcher<TriggerKey> triggerGroupContains(String compareTo) {\n        return GroupMatcher.groupContains(compareTo);\n    }\n\n    /**\n     * Create a GroupMatcher that matches groups starting with the given string.\n     */\n    public static <T extends Key<T>> GroupMatcher<T> anyGroup() {\n        return new GroupMatcher<>(\"\", StringOperatorName.ANYTHING);\n    }\n\n    /**\n     * Create a GroupMatcher that matches job groups starting with the given string.\n     */\n    public static GroupMatcher<JobKey> anyJobGroup() {\n        return GroupMatcher.anyGroup();\n    }\n\n    /**\n     * Create a GroupMatcher that matches trigger groups starting with the given string.\n     */\n    public static GroupMatcher<TriggerKey> anyTriggerGroup() {\n        return GroupMatcher.anyGroup();\n    }\n\n    @Override\n    protected String getValue(T key) {\n        return key.getGroup();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/KeyMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.Matcher;\nimport org.quartz.utils.Key;\n\n/**\n * Matches on the complete key being equal (both name and group). \n *  \n * @author jhouse\n */\npublic class KeyMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = 1230009869074992437L;\n\n    protected final T compareTo;\n    \n    protected KeyMatcher(T compareTo) {\n        this.compareTo = compareTo;\n    }\n    \n    /**\n     * Create a KeyMatcher that matches Keys that equal the given key. \n     */\n    public static <U extends Key<?>> KeyMatcher<U> keyEquals(U compareTo) {\n        return new KeyMatcher<>(compareTo);\n    }\n\n    public boolean isMatch(T key) {\n\n        return compareTo.equals(key);\n    }\n\n    public T getCompareToValue() {\n        return compareTo;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result\n                + ((compareTo == null) ? 0 : compareTo.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        KeyMatcher<?> other = (KeyMatcher<?>) obj;\n        if (compareTo == null) {\n            return other.compareTo == null;\n        } else return compareTo.equals(other.compareTo);\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/NameMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.JobKey;\nimport org.quartz.TriggerKey;\nimport org.quartz.utils.Key;\n\n/**\n * Matches on name (ignores group) property of Keys.\n *  \n * @author jhouse\n */\npublic class NameMatcher<T extends Key<?>> extends StringMatcher<T> {\n  \n    private static final long serialVersionUID = -33104959459613480L;\n\n    protected NameMatcher(String compareTo, StringOperatorName compareWith) {\n        super(compareTo, compareWith);\n    }\n    \n    /**\n     * Create a NameMatcher that matches names equaling the given string.\n     */\n    public static <T extends Key<?>> NameMatcher<T> nameEquals(String compareTo) {\n        return new NameMatcher<>(compareTo, StringOperatorName.EQUALS);\n    }\n\n    /**\n     * Create a NameMatcher that matches job names equaling the given string.\n     */\n    public static NameMatcher<JobKey> jobNameEquals(String compareTo) {\n        return NameMatcher.nameEquals(compareTo);\n    }\n    \n    /**\n     * Create a NameMatcher that matches trigger names equaling the given string.\n     */\n    public static NameMatcher<TriggerKey> triggerNameEquals(String compareTo) {\n        return NameMatcher.nameEquals(compareTo);\n    }\n    \n    /**\n     * Create a NameMatcher that matches names starting with the given string.\n     */\n    public static <U extends Key<?>> NameMatcher<U> nameStartsWith(String compareTo) {\n        return new NameMatcher<>(compareTo, StringOperatorName.STARTS_WITH);\n    }\n\n    /**\n     * Create a NameMatcher that matches job names starting with the given string.\n     */\n    public static NameMatcher<JobKey> jobNameStartsWith(String compareTo) {\n        return NameMatcher.nameStartsWith(compareTo);\n    }\n    \n    /**\n     * Create a NameMatcher that matches trigger names starting with the given string.\n     */\n    public static NameMatcher<TriggerKey> triggerNameStartsWith(String compareTo) {\n        return NameMatcher.nameStartsWith(compareTo);\n    }\n\n    /**\n     * Create a NameMatcher that matches names ending with the given string.\n     */\n    public static <U extends Key<?>> NameMatcher<U> nameEndsWith(String compareTo) {\n        return new NameMatcher<>(compareTo, StringOperatorName.ENDS_WITH);\n    }\n\n    /**\n     * Create a NameMatcher that matches job names ending with the given string.\n     */\n    public static NameMatcher<JobKey> jobNameEndsWith(String compareTo) {\n        return NameMatcher.nameEndsWith(compareTo);\n    }\n    \n    /**\n     * Create a NameMatcher that matches trigger names ending with the given string.\n     */\n    public static NameMatcher<TriggerKey> triggerNameEndsWith(String compareTo) {\n        return NameMatcher.nameEndsWith(compareTo);\n    }\n\n    /**\n     * Create a NameMatcher that matches names containing the given string.\n     */\n    public static <U extends Key<?>> NameMatcher<U> nameContains(String compareTo) {\n        return new NameMatcher<>(compareTo, StringOperatorName.CONTAINS);\n    }\n\n    /**\n     * Create a NameMatcher that matches job names containing the given string.\n     */\n    public static NameMatcher<JobKey> jobNameContains(String compareTo) {\n        return NameMatcher.nameContains(compareTo);\n    }\n    \n    /**\n     * Create a NameMatcher that matches trigger names containing the given string.\n     */\n    public static NameMatcher<TriggerKey> triggerNameContains(String compareTo) {\n        return NameMatcher.nameContains(compareTo);\n    }\n    \n    @Override\n    protected String getValue(T key) {\n        return key.getName();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/NotMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.Matcher;\nimport org.quartz.utils.Key;\n\n/**\n * Matches using an NOT operator on another Matcher. \n *  \n * @author jhouse\n */\npublic class NotMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = -2856769076151741391L;\n\n    protected Matcher<T> operand;\n    \n    protected NotMatcher(Matcher<T> operand) {\n        if(operand == null)\n            throw new IllegalArgumentException(\"Non-null operand required!\");\n        \n        this.operand = operand;\n    }\n    \n    /**\n     * Create a NotMatcher that reverses the result of the given matcher.\n     */\n    public static <U extends Key<?>> NotMatcher<U> not(Matcher<U> operand) {\n        return new NotMatcher<>(operand);\n    }\n\n    public boolean isMatch(T key) {\n\n        return !operand.isMatch(key);\n    }\n\n    public Matcher<T> getOperand() {\n        return operand;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((operand == null) ? 0 : operand.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        NotMatcher<?> other = (NotMatcher<?>) obj;\n        if (operand == null) {\n            return other.operand == null;\n        } else return operand.equals(other.operand);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/OrMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.Matcher;\nimport org.quartz.utils.Key;\n\n/**\n * Matches using an OR operator on two Matcher operands. \n *  \n * @author jhouse\n */\npublic class OrMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = -2867392824539403712L;\n\n    protected Matcher<T> leftOperand;\n    protected Matcher<T> rightOperand;\n    \n    protected OrMatcher(Matcher<T> leftOperand, Matcher<T> rightOperand) {\n        if(leftOperand == null || rightOperand == null)\n            throw new IllegalArgumentException(\"Two non-null operands required!\");\n        \n        this.leftOperand = leftOperand;\n        this.rightOperand = rightOperand;\n    }\n    \n    /**\n     * Create an OrMatcher that depends upon the result of at least one of the given matchers.\n     */\n    public static <U extends Key<?>> OrMatcher<U> or(Matcher<U> leftOperand, Matcher<U> rightOperand) {\n        return new OrMatcher<>(leftOperand, rightOperand);\n    }\n\n    public boolean isMatch(T key) {\n\n        return leftOperand.isMatch(key) || rightOperand.isMatch(key);\n    }\n\n    public Matcher<T> getLeftOperand() {\n        return leftOperand;\n    }\n\n    public Matcher<T> getRightOperand() {\n        return rightOperand;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result\n                + ((leftOperand == null) ? 0 : leftOperand.hashCode());\n        result = prime * result\n                + ((rightOperand == null) ? 0 : rightOperand.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        OrMatcher<?> other = (OrMatcher<?>) obj;\n        if (leftOperand == null) {\n            if (other.leftOperand != null)\n                return false;\n        } else if (!leftOperand.equals(other.leftOperand))\n            return false;\n        if (rightOperand == null) {\n            return other.rightOperand == null;\n        } else return rightOperand.equals(other.rightOperand);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/matchers/StringMatcher.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.matchers;\n\nimport org.quartz.Matcher;\nimport org.quartz.utils.Key;\n\n/**\n * An abstract base class for some types of matchers.\n *  \n * @author jhouse\n */\npublic abstract class StringMatcher<T extends Key<?>> implements Matcher<T> {\n  \n    private static final long serialVersionUID = -2757924162611145836L;\n\n    public enum StringOperatorName {\n\n        EQUALS {\n            @Override\n            public boolean evaluate(final String value, final String compareTo) {\n                return value.equals(compareTo);\n            }\n        },\n\n        STARTS_WITH {\n            @Override\n            public boolean evaluate(final String value, final String compareTo) {\n                return value.startsWith(compareTo);\n            }\n        },\n\n        ENDS_WITH {\n            @Override\n            public boolean evaluate(final String value, final String compareTo) {\n                return value.endsWith(compareTo);\n            }\n        },\n\n        CONTAINS {\n            @Override\n            public boolean evaluate(final String value, final String compareTo) {\n                return value.contains(compareTo);\n            }\n        },\n\n        ANYTHING {\n            @Override\n            public boolean evaluate(final String value, final String compareTo) {\n                return true;\n            }\n        };\n\n        public abstract boolean evaluate(String value, String compareTo);\n    }\n\n    protected String compareTo;\n    protected StringOperatorName compareWith;\n    \n    protected StringMatcher(String compareTo, StringOperatorName compareWith) {\n        if(compareTo == null)\n            throw new IllegalArgumentException(\"CompareTo value cannot be null!\");\n        if(compareWith == null)\n            throw new IllegalArgumentException(\"CompareWith operator cannot be null!\");\n        \n        this.compareTo = compareTo;\n        this.compareWith = compareWith;\n    }\n\n    protected abstract String getValue(T key);\n    \n    public boolean isMatch(T key) {\n\n        return compareWith.evaluate(getValue(key), compareTo);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result\n                + ((compareTo == null) ? 0 : compareTo.hashCode());\n        result = prime * result\n                + ((compareWith == null) ? 0 : compareWith.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        StringMatcher<?> other = (StringMatcher<?>) obj;\n        if (compareTo == null) {\n            if (other.compareTo != null)\n                return false;\n        } else if (!compareTo.equals(other.compareTo))\n            return false;\n        if (compareWith == null) {\n            return other.compareWith == null;\n        } else return compareWith.equals(other.compareWith);\n    }\n\n    public String getCompareToValue() {\n        return compareTo;\n    }\n\n    public StringOperatorName getCompareWithOperator() {\n        return compareWith;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.impl</title>\n</head>\n<body>\n<p>Contains implementations of the SchedulerFactory, JobStore, ThreadPool, and \nother interfaces required by the org.quartz.core.QuartzScheduler.</p>\n\n<p>Classes in this package may have dependencies on third-party packages.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project\n  for more information.\n\n</body>\n</html>\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/AbstractTrigger.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.triggers;\n\nimport org.quartz.Calendar;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.OperableTrigger;\n\n\n/**\n * <p>\n * The base abstract class to be extended by all <code>Trigger</code>s.\n * </p>\n * \n * <p>\n * <code>Triggers</code> s have a name and group associated with them, which\n * should uniquely identify them within a single <code>{@link Scheduler}</code>.\n * </p>\n * \n * <p>\n * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code> s\n * are scheduled. Many <code>Trigger</code> s can point to the same <code>Job</code>,\n * but a single <code>Trigger</code> can only point to one <code>Job</code>.\n * </p>\n * \n * <p>\n * Triggers can 'send' parameters/data to <code>Job</code>s by placing contents\n * into the <code>JobDataMap</code> on the <code>Trigger</code>.\n * </p>\n *\n * @author James House\n * @author Sharada Jambula\n */\npublic abstract class AbstractTrigger<T extends Trigger> implements OperableTrigger {\n\n    private static final long serialVersionUID = -3904243490805975570L;\n\n    /*\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    *\n    * Data members.\n    *\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    */\n\n    private String name;\n\n    private String group = Scheduler.DEFAULT_GROUP;\n\n    private String jobName;\n\n    private String jobGroup = Scheduler.DEFAULT_GROUP;\n\n    private String description;\n\n    private JobDataMap jobDataMap;\n\n    @SuppressWarnings(\"unused\")\n    private static final boolean VOLATILITY = false; // still here for serialization backward compatibility\n\n    private String calendarName = null;\n\n    private String fireInstanceId = null;\n\n    private int misfireInstruction = MISFIRE_INSTRUCTION_SMART_POLICY;\n\n    private int priority = DEFAULT_PRIORITY;\n\n    private transient TriggerKey key = null;\n\n    /*\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    *\n    * Constructors.\n    *\n    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    */\n\n\n\n    /**\n     * <p>\n     * Create a <code>Trigger</code> with no specified name, group, or <code>{@link org.quartz.JobDetail}</code>.\n     * </p>\n     * \n     * <p>\n     * Note that the {@link #setName(String)},{@link #setGroup(String)}and\n     * the {@link #setJobName(String)}and {@link #setJobGroup(String)}methods\n     * must be called before the <code>Trigger</code> can be placed into a\n     * {@link Scheduler}.\n     * </p>\n     */\n    protected AbstractTrigger() {\n        // do nothing...\n    }\n\n    /**\n     * <p>\n     * Create a <code>Trigger</code> with the given name, and default group.\n     * </p>\n     * \n     * <p>\n     * Note that the {@link #setJobName(String)}and\n     * {@link #setJobGroup(String)}methods must be called before the <code>Trigger</code>\n     * can be placed into a {@link Scheduler}.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     */\n    protected AbstractTrigger(String name) {\n        setName(name);\n        setGroup(null);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>Trigger</code> with the given name, and group.\n     * </p>\n     * \n     * <p>\n     * Note that the {@link #setJobName(String)}and\n     * {@link #setJobGroup(String)}methods must be called before the <code>Trigger</code>\n     * can be placed into a {@link Scheduler}.\n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     */\n    protected AbstractTrigger(String name, String group) {\n        setName(name);\n        setGroup(group);\n    }\n\n    /**\n     * <p>\n     * Create a <code>Trigger</code> with the given name, and group.\n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty, or the group is an empty string.\n     */\n    protected AbstractTrigger(String name, String group, String jobName, String jobGroup) {\n        setName(name);\n        setGroup(group);\n        setJobName(jobName);\n        setJobGroup(jobGroup);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name of this <code>Trigger</code>.\n     * </p>\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * <p>\n     * Set the name of this <code>Trigger</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if name is null or empty.\n     */\n    public void setName(String name) {\n        if (name == null || name.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Trigger name cannot be null or empty.\");\n        }\n\n        this.name = name;\n        this.key = null;\n    }\n\n    /**\n     * <p>\n     * Get the group of this <code>Trigger</code>.\n     * </p>\n     */\n    public String getGroup() {\n        return group;\n    }\n\n    /**\n     * <p>\n     * Set the name of this <code>Trigger</code>. \n     * </p>\n     * \n     * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if group is an empty string.\n     */\n    public void setGroup(String group) {\n        if (group != null && group.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Group name cannot be an empty string.\");\n        }\n\n        if(group == null) {\n            group = Scheduler.DEFAULT_GROUP;\n        }\n\n        this.group = group;\n        this.key = null;\n    }\n\n    public void setKey(TriggerKey key) {\n        setName(key.getName());\n        setGroup(key.getGroup());\n        this.key = key;\n    }\n\n    /**\n     * <p>\n     * Get the name of the associated <code>{@link org.quartz.JobDetail}</code>.\n     * </p>\n     */\n    public String getJobName() {\n        return jobName;\n    }\n\n    /**\n     * <p>\n     * Set the name of the associated <code>{@link org.quartz.JobDetail}</code>.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if jobName is null or empty.\n     */\n    public void setJobName(String jobName) {\n        if (jobName == null || jobName.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Job name cannot be null or empty.\");\n        }\n\n        this.jobName = jobName;\n    }\n\n    /**\n     * <p>\n     * Get the name of the associated <code>{@link org.quartz.JobDetail}</code>'s\n     * group.\n     * </p>\n     */\n    public String getJobGroup() {\n        return jobGroup;\n    }\n\n    /**\n     * <p>\n     * Set the name of the associated <code>{@link org.quartz.JobDetail}</code>'s\n     * group.\n     * </p>\n     * \n     * @param jobGroup if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.\n     * \n     * @exception IllegalArgumentException\n     *              if group is an empty string.\n     */\n    public void setJobGroup(String jobGroup) {\n        if (jobGroup != null && jobGroup.trim().isEmpty()) {\n            throw new IllegalArgumentException(\n                    \"Group name cannot be null or empty.\");\n        }\n\n        if(jobGroup == null) {\n            jobGroup = Scheduler.DEFAULT_GROUP;\n        }\n\n        this.jobGroup = jobGroup;\n    }\n\n    public void setJobKey(JobKey key) {\n        setJobName(key.getName());\n        setJobGroup(key.getGroup());\n    }\n\n\n    /**\n     * <p>\n     * Returns the 'full name' of the <code>Trigger</code> in the format\n     * \"group.name\".\n     * </p>\n     */\n    public String getFullName() {\n        return group + \".\" + name;\n    }\n\n    public TriggerKey getKey() {\n        if(key == null) {\n            if(getName() == null)\n                return null;\n            key = new TriggerKey(getName(), getGroup());\n        }\n\n        return key;\n    }\n\n    public JobKey getJobKey() {\n        if(getJobName() == null)\n            return null;\n\n        return new JobKey(getJobName(), getJobGroup());\n    }\n\n    /**\n     * <p>\n     * Returns the 'full name' of the <code>Job</code> that the <code>Trigger</code>\n     * points to, in the format \"group.name\".\n     * </p>\n     */\n    public String getFullJobName() {\n        return jobGroup + \".\" + jobName;\n    }\n\n    /**\n     * <p>\n     * Return the description given to the <code>Trigger</code> instance by\n     * its creator (if any).\n     * </p>\n     * \n     * @return null if no description was set.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * <p>\n     * Set a description for the <code>Trigger</code> instance - may be\n     * useful for remembering/displaying the purpose of the trigger, though the\n     * description has no meaning to Quartz.\n     * </p>\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * <p>\n     * Associate the <code>{@link Calendar}</code> with the given name with\n     * this Trigger.\n     * </p>\n     * \n     * @param calendarName\n     *          use <code>null</code> to dis-associate a Calendar.\n     */\n    public void setCalendarName(String calendarName) {\n        this.calendarName = calendarName;\n    }\n\n    /**\n     * <p>\n     * Get the name of the <code>{@link Calendar}</code> associated with this\n     * Trigger.\n     * </p>\n     * \n     * @return <code>null</code> if there is no associated Calendar.\n     */\n    public String getCalendarName() {\n        return calendarName;\n    }\n\n    /**\n     * <p>\n     * Get the <code>JobDataMap</code> that is associated with the \n     * <code>Trigger</code>.\n     * </p>\n     * \n     * <p>\n     * Changes made to this map during job execution are not re-persisted, and\n     * in fact typically result in an <code>IllegalStateException</code>.\n     * </p>\n     */\n    public JobDataMap getJobDataMap() {\n        if (jobDataMap == null) {\n            jobDataMap = new JobDataMap();\n        }\n        return jobDataMap;\n    }\n\n\n    /**\n     * <p>\n     * Set the <code>JobDataMap</code> to be associated with the \n     * <code>Trigger</code>.\n     * </p>\n     */\n    public void setJobDataMap(JobDataMap jobDataMap) {\n        this.jobDataMap = jobDataMap;\n    }\n\n    /**\n     * The priority of a <code>Trigger</code> acts as a tiebreaker such that if \n     * two <code>Trigger</code>s have the same scheduled fire time, then the\n     * one with the higher priority will get first access to a worker\n     * thread.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>5</code>.\n     * </p>\n     * \n     * @see #DEFAULT_PRIORITY\n     */\n    public int getPriority() {\n        return priority;\n    }\n\n\n    /**\n     * The priority of a <code>Trigger</code> acts as a tie breaker such that if \n     * two <code>Trigger</code>s have the same scheduled fire time, then Quartz\n     * will do its best to give the one with the higher priority first access \n     * to a worker thread.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>5</code>.\n     * </p>\n     * \n     * @see #DEFAULT_PRIORITY\n     */\n    public void setPriority(int priority) {\n        this.priority = priority;\n    }\n\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Called after the <code>{@link Scheduler}</code> has executed the\n     * <code>{@link org.quartz.JobDetail}</code> associated with the <code>Trigger</code>\n     * in order to get the final instruction code from the trigger.\n     * </p>\n     * \n     * @param context\n     *          is the <code>JobExecutionContext</code> that was used by the\n     *          <code>Job</code>'s<code>execute(xx)</code> method.\n     * @param result\n     *          is the <code>JobExecutionException</code> thrown by the\n     *          <code>Job</code>, if any (may be null).\n     * @return one of the CompletedExecutionInstruction constants.\n     * \n     * @see org.quartz.Trigger.CompletedExecutionInstruction\n     * @see #triggered(Calendar)\n     */\n    public CompletedExecutionInstruction executionComplete(JobExecutionContext context,\n                                          JobExecutionException result)\n    {\n        if (result != null && result.refireImmediately()) {\n            return CompletedExecutionInstruction.RE_EXECUTE_JOB;\n        }\n    \n        if (result != null && result.unscheduleFiringTrigger()) {\n            return CompletedExecutionInstruction.SET_TRIGGER_COMPLETE;\n        }\n    \n        if (result != null && result.unscheduleAllTriggers()) {\n            return CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE;\n        }\n    \n        if (!mayFireAgain()) {\n            return CompletedExecutionInstruction.DELETE_TRIGGER;\n        }\n    \n        return CompletedExecutionInstruction.NOOP;\n    }\n\n\n\n    /**\n     * <p>\n     * Set the instruction the <code>Scheduler</code> should be given for\n     * handling misfire situations for this <code>Trigger</code>- the\n     * concrete <code>Trigger</code> type that you are using will have\n     * defined a set of additional <code>MISFIRE_INSTRUCTION_XXX</code>\n     * constants that may be passed to this method.\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.\n     * </p>\n     * \n     * @see #MISFIRE_INSTRUCTION_SMART_POLICY\n     * @see #updateAfterMisfire(Calendar)\n     * @see SimpleTrigger\n     * @see CronTrigger\n     */\n    public void setMisfireInstruction(int misfireInstruction) {\n        if (!validateMisfireInstruction(misfireInstruction)) {\n            throw new IllegalArgumentException(\n                        \"The misfire instruction code is invalid for this type of trigger.\");\n        }\n        this.misfireInstruction = misfireInstruction;\n    }\n\n    protected abstract boolean validateMisfireInstruction(int candidateMisfireInstruction);\n\n    /**\n     * <p>\n     * Get the instruction the <code>Scheduler</code> should be given for\n     * handling misfire situations for this <code>Trigger</code>- the\n     * concrete <code>Trigger</code> type that you are using will have\n     * defined a set of additional <code>MISFIRE_INSTRUCTION_XXX</code>\n     * constants that may be passed to this method.\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.\n     * </p>\n     * \n     * @see #MISFIRE_INSTRUCTION_SMART_POLICY\n     * @see #updateAfterMisfire(Calendar)\n     * @see SimpleTrigger\n     * @see CronTrigger\n     */\n    public int getMisfireInstruction() {\n        return misfireInstruction;\n    }\n\n    /**\n     * <p>\n     * Validates whether the properties of the <code>JobDetail</code> are\n     * valid for submission into a <code>Scheduler</code>.\n     * \n     * @throws IllegalStateException\n     *           if a required property (such as Name, Group, Class) is not\n     *           set.\n     */\n    public void validate() throws SchedulerException {\n        if (name == null) {\n            throw new SchedulerException(\"Trigger's name cannot be null\");\n        }\n\n        if (group == null) {\n            throw new SchedulerException(\"Trigger's group cannot be null\");\n        }\n\n        if (jobName == null) {\n            throw new SchedulerException(\n                        \"Trigger's related Job's name cannot be null\");\n        }\n\n        if (jobGroup == null) {\n            throw new SchedulerException(\n                        \"Trigger's related Job's group cannot be null\");\n        }\n    }\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Usable by <code>{@link org.quartz.spi.JobStore}</code>\n     * implementations, in order to facilitate 'recognizing' instances of fired\n     * <code>Trigger</code> s as their jobs complete execution.\n     * </p>\n     * \n     *  \n     */\n    public void setFireInstanceId(String id) {\n        this.fireInstanceId = id;\n    }\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     */\n    public String getFireInstanceId() {\n        return fireInstanceId;\n    }\n\n    /**\n     * <p>\n     * Return a simple string representation of this object.\n     * </p>\n     */\n    @Override\n    public String toString() {\n        return \"Trigger '\" + getFullName() + \"':  triggerClass: '\"\n                + getClass().getName() + \" calendar: '\" + getCalendarName() \n                + \"' misfireInstruction: \" + getMisfireInstruction() \n                + \" nextFireTime: \" + getNextFireTime();\n    }\n\n    /**\n     * <p>\n     * Compare the next fire time of this <code>Trigger</code> to that of\n     * another by comparing their keys, or in other words, sorts them\n     * according to the natural (i.e. alphabetical) order of their keys.\n     * </p>\n     */\n    public int compareTo(Trigger other) {\n\n        if(other.getKey() == null && getKey() == null)\n            return 0;\n        if(other.getKey() == null)\n            return -1;\n        if(getKey() == null)\n            return 1;\n        \n        return getKey().compareTo(other.getKey());\n    }\n\n    /**\n     * Trigger equality is based upon the equality of the TriggerKey.\n     * \n     * @return true if the key of this Trigger equals that of the given Trigger.\n     */\n    @Override\n    public boolean equals(Object o) {\n        if(!(o instanceof Trigger))\n            return false;\n        \n        Trigger other = (Trigger)o;\n\n        return !(other.getKey() == null || getKey() == null) && getKey().equals(other.getKey());\n\n    }\n\n\n    @Override\n    public int hashCode() {\n        if(getKey() == null)\n            return super.hashCode();\n        \n        return getKey().hashCode();\n    }\n\n    @Override\n    public Object clone() {\n        AbstractTrigger<?> copy;\n        try {\n            copy = (AbstractTrigger<?>) super.clone();\n\n            // Shallow copy the jobDataMap.  Note that this means that if a user\n            // modifies a value object in this map from the cloned Trigger\n            // they will also be modifying this Trigger. \n            if (jobDataMap != null) {\n                copy.jobDataMap = (JobDataMap)jobDataMap.clone();\n            }\n\n        } catch (CloneNotSupportedException ex) {\n            throw new IncompatibleClassChangeError(\"Not Cloneable.\");\n        }\n        return copy;\n    }\n    \n    public TriggerBuilder<T> getTriggerBuilder() {\n        return TriggerBuilder.newTrigger()\n            .forJob(getJobKey())\n            .modifiedByCalendar(getCalendarName())\n            .usingJobData(getJobDataMap())\n            .withDescription(getDescription())\n            .endAt(getEndTime())\n            .withIdentity(getKey())\n            .withPriority(getPriority())\n            .startAt(getStartTime())\n            .withSchedule(getScheduleBuilder());\n    }\n\n    public abstract ScheduleBuilder<T> getScheduleBuilder();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/CalendarIntervalTriggerImpl.java",
    "content": "\n/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.triggers;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.CalendarIntervalTrigger;\nimport org.quartz.CronTrigger;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerUtils;\n\n\n/**\n * <p>A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * based upon repeating calendar time intervals.</p>\n * \n * <p>The trigger will fire every N (see {@link #setRepeatInterval(int)} ) units of calendar time\n * (see {@link #setRepeatIntervalUnit(org.quartz.DateBuilder.IntervalUnit)}) as specified in the trigger's definition.\n * This trigger can achieve schedules that are not possible with {@link SimpleTrigger} (e.g \n * because months are not a fixed number of seconds) or {@link CronTrigger} (e.g. because\n * \"every 5 months\" is not an even divisor of 12).</p>\n * \n * <p>If you use an interval unit of <code>MONTH</code> then care should be taken when setting\n * a <code>startTime</code> value that is on a day near the end of the month.  For example,\n * if you choose a start time that occurs on January 31st, and have a trigger with unit\n * <code>MONTH</code> and interval <code>1</code>, then the next fire time will be February 28th, \n * and the next time after that will be March 28th - and essentially each subsequent firing will \n * occur on the 28th of the month, even if a 31st day exists.  If you want a trigger that always\n * fires on the last day of the month - regardless of the number of days in the month, \n * you should use <code>CronTrigger</code>.</p> \n * \n * @see Trigger\n * @see CronTrigger\n * @see SimpleTrigger\n * @see TriggerUtils\n * \n * @since 1.7\n * \n * @author James House\n */\npublic class CalendarIntervalTriggerImpl extends AbstractTrigger<CalendarIntervalTrigger> implements CalendarIntervalTrigger, CoreTrigger {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private static final long serialVersionUID = -2635982274232850343L;\n\n    \n    private static final int YEAR_TO_GIVEUP_SCHEDULING_AT = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR) + 100;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    private Date startTime = null;\n\n    private Date endTime = null;\n\n    private Date nextFireTime = null;\n\n    private Date previousFireTime = null;\n\n    private  int repeatInterval = 0;\n    \n    private IntervalUnit repeatIntervalUnit = IntervalUnit.DAY;\n\n    private TimeZone timeZone;\n\n    private boolean preserveHourOfDayAcrossDaylightSavings = false; // false is backward-compatible with behavior\n\n    private boolean skipDayIfHourDoesNotExist = false;\n\n    private int timesTriggered = 0;\n\n    private final boolean complete = false;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> with no settings.\n     * </p>\n     */\n    public CalendarIntervalTriggerImpl() {\n        super();\n    }\n\n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> that will occur immediately, and\n     * repeat at the given interval.\n     * </p>\n     */\n    public CalendarIntervalTriggerImpl(String name, IntervalUnit intervalUnit,  int repeatInterval) {\n        this(name, null, intervalUnit, repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> that will occur immediately, and\n     * repeat at the given interval.\n     * </p>\n     */\n    public CalendarIntervalTriggerImpl(String name, String group, IntervalUnit intervalUnit,\n            int repeatInterval) {\n        this(name, group, new Date(), null, intervalUnit, repeatInterval);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> that will occur at the given time,\n     * and repeat at the given interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param intervalUnit\n     *          The repeat interval unit (minutes, days, months, etc).\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     */\n    public CalendarIntervalTriggerImpl(String name, Date startTime,\n            Date endTime, IntervalUnit intervalUnit,  int repeatInterval) {\n        this(name, null, startTime, endTime, intervalUnit, repeatInterval);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> that will occur at the given time,\n     * and repeat at the given interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param intervalUnit\n     *          The repeat interval unit (minutes, days, months, etc).\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     */\n    public CalendarIntervalTriggerImpl(String name, String group, Date startTime,\n            Date endTime, IntervalUnit intervalUnit,  int repeatInterval) {\n        super(name, group);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatIntervalUnit(intervalUnit);\n        setRepeatInterval(repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>DateIntervalTrigger</code> that will occur at the given time,\n     * fire the identified <code>Job</code> and repeat at the given\n     * interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param intervalUnit\n     *          The repeat interval unit (minutes, days, months, etc).\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     */\n    public CalendarIntervalTriggerImpl(String name, String group, String jobName,\n            String jobGroup, Date startTime, Date endTime,  \n            IntervalUnit intervalUnit,  int repeatInterval) {\n        super(name, group, jobName, jobGroup);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatIntervalUnit(intervalUnit);\n        setRepeatInterval(repeatInterval);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the time at which the <code>DateIntervalTrigger</code> should occur.\n     * </p>\n     */\n    @Override\n    public Date getStartTime() {\n        if(startTime == null)\n            startTime = new Date();\n        return startTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>DateIntervalTrigger</code> should occur.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if startTime is <code>null</code>.\n     */\n    @Override\n    public void setStartTime(Date startTime) {\n        if (startTime == null) {\n            throw new IllegalArgumentException(\"Start time cannot be null\");\n        }\n\n        Date eTime = getEndTime();\n        if (eTime != null && eTime.before(startTime)) {\n            throw new IllegalArgumentException(\n                \"End time cannot be before start time\");    \n        }\n\n        this.startTime = startTime;\n    }\n\n    /**\n     * <p>\n     * Get the time at which the <code>DateIntervalTrigger</code> should quit\n     * repeating.\n     * </p>\n     * \n     * @see #getFinalFireTime()\n     */\n    @Override\n    public Date getEndTime() {\n        return endTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>DateIntervalTrigger</code> should quit\n     * repeating (and be automatically deleted).\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if endTime is before start time.\n     */\n    @Override\n    public void setEndTime(Date endTime) {\n        Date sTime = getStartTime();\n        if (sTime != null && endTime != null && sTime.after(endTime)) {\n            throw new IllegalArgumentException(\n                    \"End time cannot be before start time\");\n        }\n\n        this.endTime = endTime;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.DateIntervalTriggerI#getRepeatIntervalUnit()\n     */\n    public IntervalUnit getRepeatIntervalUnit() {\n        return repeatIntervalUnit;\n    }\n\n    /**\n     * <p>Set the interval unit - the time unit on with the interval applies.</p>\n     */\n    public void setRepeatIntervalUnit(IntervalUnit intervalUnit) {\n        this.repeatIntervalUnit = intervalUnit;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.DateIntervalTriggerI#getRepeatInterval()\n     */\n    public int getRepeatInterval() {\n        return repeatInterval;\n    }\n\n    /**\n     * <p>\n     * set the time interval that will be added to the <code>DateIntervalTrigger</code>'s\n     * fire time (in the set repeat interval unit) in order to calculate the time of the \n     * next trigger repeat.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if repeatInterval is &lt; 1\n     */\n    public void setRepeatInterval( int repeatInterval) {\n        if (repeatInterval < 0) {\n            throw new IllegalArgumentException(\n                    \"Repeat interval must be >= 1\");\n        }\n\n        this.repeatInterval = repeatInterval;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.CalendarIntervalTriggerI#getTimeZone()\n     */\n    public TimeZone getTimeZone() {\n        \n        if (timeZone == null) {\n            timeZone = TimeZone.getDefault();\n        }\n        return timeZone;\n    }\n\n    /**\n     * <p>\n     * Sets the time zone within which time calculations related to this \n     * trigger will be performed.\n     * </p>\n     *\n     * @param timeZone the desired TimeZone, or null for the system default.\n     */\n    public void setTimeZone(TimeZone timeZone) {\n        this.timeZone = timeZone;\n    }\n    \n    /**\n     * If intervals are a day or greater, this property (set to true) will \n     * cause the firing of the trigger to always occur at the same time of day,\n     * (the time of day of the startTime) regardless of daylight saving time \n     * transitions.  Default value is false.\n     * \n     * <p>\n     * For example, without the property set, your trigger may have a start \n     * time of 9:00 am on March 1st, and a repeat interval of 2 days.  But \n     * after the daylight saving transition occurs, the trigger may start \n     * firing at 8:00 am every other day.\n     * </p>\n     * \n     * <p>\n     * If however, the time of day does not exist on a given day to fire\n     * (e.g. 2:00 am in the United States on the days of daylight saving\n     * transition), the trigger will go ahead and fire one hour off on \n     * that day, and then resume the normal hour on other days.  If\n     * you wish for the trigger to never fire at the \"wrong\" hour, then\n     * you should set the property skipDayIfHourDoesNotExist.\n     * </p>\n     * \n     * @see #isSkipDayIfHourDoesNotExist()\n     * @see #getStartTime()\n     * @see #getTimeZone()\n     */\n    public boolean isPreserveHourOfDayAcrossDaylightSavings() {\n        return preserveHourOfDayAcrossDaylightSavings;\n    }\n\n    public void setPreserveHourOfDayAcrossDaylightSavings(boolean preserveHourOfDayAcrossDaylightSavings) {\n        this.preserveHourOfDayAcrossDaylightSavings = preserveHourOfDayAcrossDaylightSavings;\n    }\n    \n    /**\n     * If intervals are a day or greater, and \n     * preserveHourOfDayAcrossDaylightSavings property is set to true, and the\n     * hour of the day does not exist on a given day for which the trigger \n     * would fire, the day will be skipped and the trigger advanced a second\n     * interval if this property is set to true.  Defaults to false.\n     * \n     * <p>\n     * <b>CAUTION!</b>  If you enable this property, and your hour of day happens \n     * to be that of daylight savings transition (e.g. 2:00 am in the United \n     * States) and the trigger's interval would have had the trigger fire on\n     * that day, then you may actually completely miss a firing on the day of \n     * transition if that hour of day does not exist on that day!  In such a \n     * case the next fire time of the trigger will be computed as double (if \n     * the interval is 2 days, then a span of 4 days between firings will \n     * occur).\n     * </p>\n     * \n     * @see #isPreserveHourOfDayAcrossDaylightSavings()\n     */\n    public boolean isSkipDayIfHourDoesNotExist() {\n        return skipDayIfHourDoesNotExist;\n    }\n\n    public void setSkipDayIfHourDoesNotExist(boolean skipDayIfHourDoesNotExist) {\n        this.skipDayIfHourDoesNotExist = skipDayIfHourDoesNotExist;\n    }\n    \n    /* (non-Javadoc)\n     * @see org.quartz.DateIntervalTriggerI#getTimesTriggered()\n     */\n    public int getTimesTriggered() {\n        return timesTriggered;\n    }\n\n    /**\n     * <p>\n     * Set the number of times the <code>DateIntervalTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    public void setTimesTriggered(int timesTriggered) {\n        this.timesTriggered = timesTriggered;\n    }\n\n    @Override\n    protected boolean validateMisfireInstruction(int misfireInstruction) {\n        if (misfireInstruction < MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {\n            return false;\n        }\n\n        return misfireInstruction <= MISFIRE_INSTRUCTION_DO_NOTHING;\n    }\n\n\n    /**\n     * <p>\n     * Updates the <code>DateIntervalTrigger</code>'s state based on the\n     * MISFIRE_INSTRUCTION_XXX that was selected when the <code>DateIntervalTrigger</code>\n     * was created.\n     * </p>\n     * \n     * <p>\n     * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,\n     * then the following scheme will be used: </p>\n     * <ul>\n     * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>\n     * </ul>\n     */\n    @Override\n    public void updateAfterMisfire(org.quartz.Calendar cal) {\n        int instr = getMisfireInstruction();\n\n        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)\n            return;\n\n        if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {\n            instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        }\n\n        if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {\n            Date newFireTime = getFireTimeAfter(new Date());\n            while (newFireTime != null && cal != null\n                    && !cal.isTimeIncluded(newFireTime.getTime())) {\n                newFireTime = getFireTimeAfter(newFireTime);\n            }\n            setNextFireTime(newFireTime);\n        } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { \n            // fire once now...\n            setNextFireTime(new Date());\n            // the new fire time afterward will magically preserve the original  \n            // time of day for firing for day/week/month interval triggers, \n            // because of the way getFireTimeAfter() works - in its always restarting\n            // computation from the start time.\n        }\n    }\n\n    /**\n     * <p>\n     * Called when the <code>{@link Scheduler}</code> has decided to 'fire'\n     * the trigger (execute the associated <code>Job</code>), in order to\n     * give the <code>Trigger</code> a chance to update itself for its next\n     * triggering (if any).\n     * </p>\n     * \n     * @see #executionComplete(JobExecutionContext, JobExecutionException)\n     */\n    @Override\n    public void triggered(org.quartz.Calendar calendar) {\n        timesTriggered++;\n        previousFireTime = nextFireTime;\n        nextFireTime = getFireTimeAfter(nextFireTime);\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            \n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n        }\n    }\n\n\n    /**\n     *  \n     * @see org.quartz.spi.OperableTrigger#updateWithNewCalendar(org.quartz.Calendar, long)\n     */\n    @Override\n    public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold)\n    {\n        nextFireTime = getFireTimeAfter(previousFireTime);\n\n        if (nextFireTime == null || calendar == null) {\n            return;\n        }\n        \n        Date now = new Date();\n        while (nextFireTime != null && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n\n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n\n            if(nextFireTime != null && nextFireTime.before(now)) {\n                long diff = now.getTime() - nextFireTime.getTime();\n                if(diff >= misfireThreshold) {\n                    nextFireTime = getFireTimeAfter(nextFireTime);\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Called by the scheduler at the time a <code>Trigger</code> is first\n     * added to the scheduler, in order to have the <code>Trigger</code>\n     * compute its first fire time, based on any associated calendar.\n     * </p>\n     * \n     * <p>\n     * After this method has been called, <code>getNextFireTime()</code>\n     * should return a valid answer.\n     * </p>\n     * \n     * @return the first time at which the <code>Trigger</code> will be fired\n     *         by the scheduler, which is also the same value <code>getNextFireTime()</code>\n     *         will return (until after the first firing of the <code>Trigger</code>).\n     */\n    @Override\n    public Date computeFirstFireTime(org.quartz.Calendar calendar) {\n        nextFireTime = getStartTime();\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            \n            nextFireTime = getFireTimeAfter(nextFireTime);\n            \n            if(nextFireTime == null)\n                break;\n\n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                return null;\n            }\n        }\n        \n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>Trigger</code> is scheduled to fire. If\n     * the trigger will not fire again, <code>null</code> will be returned.  Note that\n     * the time returned can possibly be in the past, if the time that was computed\n     * for the trigger to next fire has already arrived, but the scheduler has not yet\n     * been able to fire the trigger (which would likely be due to lack of resources\n     * e.g. threads).\n     * </p>\n     *\n     * <p>The value returned is not guaranteed to be valid until after the <code>Trigger</code>\n     * has been added to the scheduler.\n     * </p>\n     */\n    @Override\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the previous time at which the <code>DateIntervalTrigger</code> \n     * fired. If the trigger has not yet fired, <code>null</code> will be\n     * returned.\n     */\n    @Override\n    public Date getPreviousFireTime() {\n        return previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the next time at which the <code>DateIntervalTrigger</code> should fire.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setNextFireTime(Date nextFireTime) {\n        this.nextFireTime = nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the previous time at which the <code>DateIntervalTrigger</code> fired.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setPreviousFireTime(Date previousFireTime) {\n        this.previousFireTime = previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>DateIntervalTrigger</code> will\n     * fire, after the given time. If the trigger will not fire after the given\n     * time, <code>null</code> will be returned.\n     * </p>\n     */\n    @Override\n    public Date getFireTimeAfter(Date afterTime) {\n        return getFireTimeAfter(afterTime, false);\n    }\n    \n    protected Date getFireTimeAfter(Date afterTime, boolean ignoreEndTime) {\n        if (complete) {\n            return null;\n        }\n\n        // increment afterTime by a second, so that we are \n        // comparing against a time after it!\n        if (afterTime == null) {\n            afterTime = new Date();\n        }\n\n        long startMillis = getStartTime().getTime();\n        long afterMillis = afterTime.getTime();\n        long endMillis = (getEndTime() == null) ? Long.MAX_VALUE : getEndTime()\n                .getTime();\n\n        if (!ignoreEndTime && (endMillis <= afterMillis)) {\n            return null;\n        }\n\n        if (afterMillis < startMillis) {\n            return new Date(startMillis);\n        }\n\n        \n        long secondsAfterStart = 1 + (afterMillis - startMillis) / 1000L;\n\n        Date time = null;\n        long repeatLong = getRepeatInterval();\n        \n        Calendar aTime = Calendar.getInstance();\n        aTime.setTime(afterTime);\n\n        Calendar sTime = Calendar.getInstance();\n        if(timeZone != null)\n            sTime.setTimeZone(timeZone);\n        sTime.setTime(getStartTime());\n        sTime.setLenient(true);\n        \n        if(getRepeatIntervalUnit().equals(IntervalUnit.SECOND)) {\n            long jumpCount = secondsAfterStart / repeatLong;\n            if(secondsAfterStart % repeatLong != 0)\n                jumpCount++;\n            sTime.add(Calendar.SECOND, getRepeatInterval() * (int)jumpCount);\n            time = sTime.getTime();\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.MINUTE)) {\n            long jumpCount = secondsAfterStart / (repeatLong * 60L);\n            if(secondsAfterStart % (repeatLong * 60L) != 0)\n                jumpCount++;\n            sTime.add(Calendar.MINUTE, getRepeatInterval() * (int)jumpCount);\n            time = sTime.getTime();\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.HOUR)) {\n            long jumpCount = secondsAfterStart / (repeatLong * 60L * 60L);\n            if(secondsAfterStart % (repeatLong * 60L * 60L) != 0)\n                jumpCount++;\n            sTime.add(Calendar.HOUR_OF_DAY, getRepeatInterval() * (int)jumpCount);\n            time = sTime.getTime();\n        }\n        else { // intervals a day or greater ...\n\n            int initialHourOfDay = sTime.get(Calendar.HOUR_OF_DAY);\n            \n            if(getRepeatIntervalUnit().equals(IntervalUnit.DAY)) {\n                sTime.setLenient(true);\n                \n                // Because intervals greater than an hour have an non-fixed number \n                // of seconds in them (due to daylight savings, variation number of \n                // days in each month, leap year, etc. ) we can't jump forward an\n                // exact number of seconds to calculate the fire time as we can\n                // with the second, minute and hour intervals.   But, rather\n                // than slowly crawling our way there by iteratively adding the \n                // increment to the start time until we reach the \"after time\",\n                // we can first make a big leap most of the way there...\n                \n                long jumpCount = secondsAfterStart / (repeatLong * 24L * 60L * 60L);\n                // if we need to make a big jump, jump most of the way there, \n                // but not all the way because in some cases we may over-shoot or under-shoot\n                if(jumpCount > 20) {\n                    if(jumpCount < 50)\n                        jumpCount = (long) (jumpCount * 0.80);\n                    else if(jumpCount < 500)\n                        jumpCount = (long) (jumpCount * 0.90);\n                    else\n                        jumpCount = (long) (jumpCount * 0.95);\n                    sTime.add(java.util.Calendar.DAY_OF_YEAR, (int) (getRepeatInterval() * jumpCount));\n                }\n                \n                // now baby-step the rest of the way there...\n                while(!sTime.getTime().after(afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {            \n                    sTime.add(java.util.Calendar.DAY_OF_YEAR, getRepeatInterval());\n                }\n                while(daylightSavingHourShiftOccurredAndAdvanceNeeded(sTime, initialHourOfDay, afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {\n                    sTime.add(java.util.Calendar.DAY_OF_YEAR, getRepeatInterval());\n                }\n                time = sTime.getTime();\n            }\n            else if(getRepeatIntervalUnit().equals(IntervalUnit.WEEK)) {\n                sTime.setLenient(true);\n    \n                // Because intervals greater than an hour have an non-fixed number \n                // of seconds in them (due to daylight savings, variation number of \n                // days in each month, leap year, etc. ) we can't jump forward an\n                // exact number of seconds to calculate the fire time as we can\n                // with the second, minute and hour intervals.   But, rather\n                // than slowly crawling our way there by iteratively adding the \n                // increment to the start time until we reach the \"after time\",\n                // we can first make a big leap most of the way there...\n                \n                long jumpCount = secondsAfterStart / (repeatLong * 7L * 24L * 60L * 60L);\n                // if we need to make a big jump, jump most of the way there, \n                // but not all the way because in some cases we may over-shoot or under-shoot\n                if(jumpCount > 20) {\n                    if(jumpCount < 50)\n                        jumpCount = (long) (jumpCount * 0.80);\n                    else if(jumpCount < 500)\n                        jumpCount = (long) (jumpCount * 0.90);\n                    else\n                        jumpCount = (long) (jumpCount * 0.95);\n                    sTime.add(java.util.Calendar.WEEK_OF_YEAR, (int) (getRepeatInterval() * jumpCount));\n                }\n                \n                while(!sTime.getTime().after(afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {            \n                    sTime.add(java.util.Calendar.WEEK_OF_YEAR, getRepeatInterval());\n                }\n                while(daylightSavingHourShiftOccurredAndAdvanceNeeded(sTime, initialHourOfDay, afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {\n                    sTime.add(java.util.Calendar.WEEK_OF_YEAR, getRepeatInterval());\n                }\n                time = sTime.getTime();\n            }\n            else if(getRepeatIntervalUnit().equals(IntervalUnit.MONTH)) {\n                sTime.setLenient(true);\n    \n                // because of the large variation in size of months, and \n                // because months are already large blocks of time, we will\n                // just advance via brute-force iteration.\n                \n                while(!sTime.getTime().after(afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {            \n                    sTime.add(java.util.Calendar.MONTH, getRepeatInterval());\n                }\n                while(daylightSavingHourShiftOccurredAndAdvanceNeeded(sTime, initialHourOfDay, afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {\n                    sTime.add(java.util.Calendar.MONTH, getRepeatInterval());\n                }\n                time = sTime.getTime();\n            }\n            else if(getRepeatIntervalUnit().equals(IntervalUnit.YEAR)) {\n    \n                while(!sTime.getTime().after(afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {            \n                    sTime.add(java.util.Calendar.YEAR, getRepeatInterval());\n                }\n                while(daylightSavingHourShiftOccurredAndAdvanceNeeded(sTime, initialHourOfDay, afterTime) &&\n                        (sTime.get(java.util.Calendar.YEAR) < YEAR_TO_GIVEUP_SCHEDULING_AT)) {\n                    sTime.add(java.util.Calendar.YEAR, getRepeatInterval());\n                }\n                time = sTime.getTime();\n            }\n        } // case of interval of a day or greater\n        \n        if (!ignoreEndTime && (endMillis <= time.getTime())) {\n            return null;\n        }\n\n        return time;\n    }\n\n    private boolean daylightSavingHourShiftOccurredAndAdvanceNeeded(Calendar newTime, int initialHourOfDay, Date afterTime) {\n        if(isPreserveHourOfDayAcrossDaylightSavings() && newTime.get(Calendar.HOUR_OF_DAY) != initialHourOfDay) {\n            newTime.set(Calendar.HOUR_OF_DAY, initialHourOfDay);\n            if (newTime.get(Calendar.HOUR_OF_DAY) != initialHourOfDay) {\n                return isSkipDayIfHourDoesNotExist();\n            } else {\n                return !newTime.getTime().after(afterTime);\n            }\n        }\n        return false;\n    }\n    \n    /**\n     * <p>\n     * Returns the final time at which the <code>DateIntervalTrigger</code> will\n     * fire, if there is no end time set, null will be returned.\n     * </p>\n     * \n     * <p>\n     * Note that the return time may be in the past.\n     * </p>\n     */\n    @Override\n    public Date getFinalFireTime() {\n        if (complete || getEndTime() == null) {\n            return null;\n        }\n\n        // back up a second from end time\n        Date fTime = new Date(getEndTime().getTime() - 1000L);\n        // find the next fire time after that\n        fTime = getFireTimeAfter(fTime, true);\n        \n        // the trigger fires at the end time, that's it!\n        if(fTime.equals(getEndTime()))\n            return fTime;\n        \n        // otherwise we have to back up one interval from the fire time after the end time\n        \n        Calendar lTime = Calendar.getInstance();\n        if(timeZone != null)\n            lTime.setTimeZone(timeZone);\n        lTime.setTime(fTime);\n        lTime.setLenient(true);\n        \n        if(getRepeatIntervalUnit().equals(IntervalUnit.SECOND)) {\n            lTime.add(java.util.Calendar.SECOND, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.MINUTE)) {\n            lTime.add(java.util.Calendar.MINUTE, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.HOUR)) {\n            lTime.add(java.util.Calendar.HOUR_OF_DAY, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.DAY)) {\n            lTime.add(java.util.Calendar.DAY_OF_YEAR, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.WEEK)) {\n            lTime.add(java.util.Calendar.WEEK_OF_YEAR, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.MONTH)) {\n            lTime.add(java.util.Calendar.MONTH, -1 * getRepeatInterval());\n        }\n        else if(getRepeatIntervalUnit().equals(IntervalUnit.YEAR)) {\n            lTime.add(java.util.Calendar.YEAR, -1 * getRepeatInterval());\n        }\n\n        return lTime.getTime();\n    }\n\n    /**\n     * <p>\n     * Determines whether or not the <code>DateIntervalTrigger</code> will occur\n     * again.\n     * </p>\n     */\n    @Override\n    public boolean mayFireAgain() {\n        return (getNextFireTime() != null);\n    }\n\n    /**\n     * <p>\n     * Validates whether the properties of the <code>JobDetail</code> are\n     * valid for submission into a <code>Scheduler</code>.\n     * \n     * @throws IllegalStateException\n     *           if a required property (such as Name, Group, Class) is not\n     *           set.\n     */\n    @Override\n    public void validate() throws SchedulerException {\n        super.validate();\n        \n        if (repeatInterval < 1) {\n            throw new SchedulerException(\"Repeat Interval cannot be zero.\");\n        }\n    }\n\n    /**\n     * Get a {@link ScheduleBuilder} that is configured to produce a \n     * schedule identical to this trigger's schedule.\n     * \n     * @see #getTriggerBuilder()\n     */\n    @Override\n    public ScheduleBuilder<CalendarIntervalTrigger> getScheduleBuilder() {\n        \n        CalendarIntervalScheduleBuilder cb = CalendarIntervalScheduleBuilder.calendarIntervalSchedule()\n                .withInterval(getRepeatInterval(), getRepeatIntervalUnit());\n            \n        switch(getMisfireInstruction()) {\n            case MISFIRE_INSTRUCTION_DO_NOTHING : cb.withMisfireHandlingInstructionDoNothing();\n            break;\n            case MISFIRE_INSTRUCTION_FIRE_ONCE_NOW : cb.withMisfireHandlingInstructionFireAndProceed();\n            break;\n        }\n        \n        return cb;\n    }\n\n    public boolean hasAdditionalProperties() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/CoreTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.triggers;\n\nimport org.quartz.Trigger;\n\n/**\n * internal interface preserved for backward compatibility \n */\npublic interface CoreTrigger extends Trigger {\n\n    boolean hasAdditionalProperties();\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/CronTriggerImpl.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.triggers;\n\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport org.quartz.CronExpression;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.Scheduler;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * <p>\n * A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * at given moments in time, defined with Unix 'cron-like' definitions.\n * </p>\n * \n * \n * @author Sharada Jambula, James House\n * @author Contributions from Mads Henderson\n */\npublic class CronTriggerImpl extends AbstractTrigger<CronTrigger> implements CronTrigger, CoreTrigger {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Required for serialization support. Introduced in Quartz 1.6.1 to \n     * maintain compatibility after the introduction of hasAdditionalProperties\n     * method. \n     * \n     * @see java.io.Serializable\n     */\n    private static final long serialVersionUID = -8644953146451592766L;\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CronTriggerImpl.class);\n\n    protected static final int YEAR_TO_GIVEUP_SCHEDULING_AT = CronExpression.MAX_YEAR;\n    \n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private CronExpression cronEx = null;\n    private Date startTime = null;\n    private Date endTime = null;\n    private Date nextFireTime = null;\n    private Date previousFireTime = null;\n    private transient TimeZone timeZone = null;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>CronTrigger</code> with no settings.\n     * </p>\n     * \n     * <p>\n     * The start-time will also be set to the current time, and the time zone\n     * will be set the system's default time zone.\n     * </p>\n     */\n    public CronTriggerImpl() {\n        super();\n        setStartTime(new Date());\n        setTimeZone(TimeZone.getDefault());\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    @Override\n    public Object clone() {\n        CronTriggerImpl copy = (CronTriggerImpl) super.clone();\n        if (cronEx != null) {\n            copy.setCronExpression(new CronExpression(cronEx));\n        }\n        return copy;\n    }\n\n    public void setCronExpression(String cronExpression) throws ParseException {\n        TimeZone origTz = getTimeZone();\n        this.cronEx = new CronExpression(cronExpression);\n        this.cronEx.setTimeZone(origTz);\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.CronTriggerI#getCronExpression()\n     */\n    public String getCronExpression() {\n        return cronEx == null ? null : cronEx.getCronExpression();\n    }\n\n    /**\n     * Set the CronExpression to the given one.  The TimeZone on the passed-in\n     * CronExpression over-rides any that was already set on the Trigger.\n     */\n    public void setCronExpression(CronExpression cronExpression) {\n        this.cronEx = cronExpression;\n        this.timeZone = cronExpression.getTimeZone();\n    }\n    \n    /**\n     * <p>\n     * Get the time at which the <code>CronTrigger</code> should occur.\n     * </p>\n     */\n    @Override\n    public Date getStartTime() {\n        return this.startTime;\n    }\n\n    @Override\n    public void setStartTime(Date startTime) {\n        if (startTime == null) {\n            throw new IllegalArgumentException(\"Start time cannot be null\");\n        }\n\n        Date eTime = getEndTime();\n        if (eTime != null && eTime.before(startTime)) {\n            throw new IllegalArgumentException(\n                \"End time cannot be before start time\");\n        }\n        \n        // round off millisecond...\n        // Note timeZone is not needed here as parameter for\n        // Calendar.getInstance(),\n        // since time zone is implicit when using a Date in the setTime method.\n        Calendar cl = Calendar.getInstance();\n        cl.setTime(startTime);\n        cl.set(Calendar.MILLISECOND, 0);\n\n        this.startTime = cl.getTime();\n    }\n\n    /**\n     * <p>\n     * Get the time at which the <code>CronTrigger</code> should quit\n     * repeating - even if repeatCount isn't yet satisfied.\n     * </p>\n     * \n     * @see #getFinalFireTime()\n     */\n    @Override\n    public Date getEndTime() {\n        return this.endTime;\n    }\n\n    @Override\n    public void setEndTime(Date endTime) {\n        Date sTime = getStartTime();\n        if (sTime != null && endTime != null && sTime.after(endTime)) {\n            throw new IllegalArgumentException(\n                    \"End time cannot be before start time\");\n        }\n\n        this.endTime = endTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>Trigger</code> is scheduled to fire. If\n     * the trigger will not fire again, <code>null</code> will be returned.  Note that\n     * the time returned can possibly be in the past, if the time that was computed\n     * for the trigger to next fire has already arrived, but the scheduler has not yet\n     * been able to fire the trigger (which would likely be due to lack of resources\n     * e.g. threads).\n     * </p>\n     *\n     * <p>The value returned is not guaranteed to be valid until after the <code>Trigger</code>\n     * has been added to the scheduler.\n     * </p>\n     *\n     * @see TriggerUtils#computeFireTimesBetween(org.quartz.spi.OperableTrigger, org.quartz.Calendar, java.util.Date, java.util.Date)\n     */\n    @Override\n    public Date getNextFireTime() {\n        return this.nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the previous time at which the <code>CronTrigger</code> \n     * fired. If the trigger has not yet fired, <code>null</code> will be\n     * returned.\n     */\n    @Override\n    public Date getPreviousFireTime() {\n        return this.previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Sets the next time at which the <code>CronTrigger</code> will fire.\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setNextFireTime(Date nextFireTime) {\n        this.nextFireTime = nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the previous time at which the <code>CronTrigger</code> fired.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setPreviousFireTime(Date previousFireTime) {\n        this.previousFireTime = previousFireTime;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.CronTriggerI#getTimeZone()\n     */\n    public TimeZone getTimeZone() {\n        \n        if(cronEx != null) {\n            return cronEx.getTimeZone();\n        }\n        \n        if (timeZone == null) {\n            timeZone = TimeZone.getDefault();\n        }\n        return timeZone;\n    }\n\n    /**\n     * <p>\n     * Sets the time zone for which the <code>cronExpression</code> of this\n     * <code>CronTrigger</code> will be resolved.\n     * </p>\n     * \n     * <p>If {@link #setCronExpression(CronExpression)} is called after this\n     * method, the TimeZon setting on the CronExpression will \"win\".  However\n     * if {@link #setCronExpression(String)} is called after this method, the\n     * time zone applied by this method will remain in effect, since the \n     * String cron expression does not carry a time zone!\n     */\n    public void setTimeZone(TimeZone timeZone) {\n        if(cronEx != null) {\n            cronEx.setTimeZone(timeZone);\n        }\n        this.timeZone = timeZone;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>CronTrigger</code> will fire,\n     * after the given time. If the trigger will not fire after the given time,\n     * <code>null</code> will be returned.\n     * </p>\n     * \n     * <p>\n     * Note that the date returned is NOT validated against the related\n     * org.quartz.Calendar (if any)\n     * </p>\n     */\n    @Override\n    public Date getFireTimeAfter(Date afterTime) {\n        if (afterTime == null) {\n            afterTime = new Date();\n        }\n\n        if (getStartTime().after(afterTime)) {\n            afterTime = new Date(getStartTime().getTime() - 1000L);\n        }\n\n        if (getEndTime() != null && (afterTime.compareTo(getEndTime()) >= 0)) {\n            return null;\n        }\n        \n        Date pot = getTimeAfter(afterTime);\n        if (getEndTime() != null && pot != null && pot.after(getEndTime())) {\n            return null;\n        }\n\n        return pot;\n    }\n\n    /**\n     * <p>\n     * NOT YET IMPLEMENTED: Returns the final time at which the \n     * <code>CronTrigger</code> will fire.\n     * </p>\n     * \n     * <p>\n     * Note that the return time *may* be in the past. and the date returned is\n     * not validated against org.quartz.calendar\n     * </p>\n     */\n    @Override\n    public Date getFinalFireTime() {\n        Date resultTime;\n        if (getEndTime() != null) {\n            resultTime = getTimeBefore(new Date(getEndTime().getTime() + 1000L));\n        } else {\n            resultTime = (cronEx == null) ? null : cronEx.getFinalFireTime();\n        }\n        \n        if ((resultTime != null) && (getStartTime() != null) && (resultTime.before(getStartTime()))) {\n            return null;\n        } \n        \n        return resultTime;\n    }\n\n    /**\n     * <p>\n     * Determines whether or not the <code>CronTrigger</code> will occur\n     * again.\n     * </p>\n     */\n    @Override\n    public boolean mayFireAgain() {\n        return (getNextFireTime() != null);\n    }\n\n    @Override\n    protected boolean validateMisfireInstruction(int misfireInstruction) {\n        return misfireInstruction >= MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY && misfireInstruction <= MISFIRE_INSTRUCTION_DO_NOTHING;\n    }\n\n    /**\n     * <p>\n     * Updates the <code>CronTrigger</code>'s state based on the\n     * MISFIRE_INSTRUCTION_XXX that was selected when the <code>CronTrigger</code>\n     * was created.\n     * </p>\n     * \n     * <p>\n     * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,\n     * then the following scheme will be used: </p>\n     * <ul>\n     * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>\n     * </ul>\n     */\n    @Override\n    public void updateAfterMisfire(org.quartz.Calendar cal) {\n        int instr = getMisfireInstruction();\n\n        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)\n            return;\n\n        if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {\n            instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        }\n\n        if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {\n            Date newFireTime = getFireTimeAfter(new Date());\n            while (newFireTime != null && cal != null\n                    && !cal.isTimeIncluded(newFireTime.getTime())) {\n                newFireTime = getFireTimeAfter(newFireTime);\n            }\n            setNextFireTime(newFireTime);\n        } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {\n            setNextFireTime(new Date());\n        }\n    }\n\n    /**\n     * <p>\n     * Determines whether the date and (optionally) time of the given Calendar \n     * instance falls on a scheduled fire-time of this trigger.\n     * </p>\n     * \n     * <p>\n     * Equivalent to calling <code>willFireOn(cal, false)</code>.\n     * </p>\n     * \n     * @param test the date to compare\n     * \n     * @see #willFireOn(Calendar, boolean)\n     */\n    public boolean willFireOn(Calendar test) {\n        return willFireOn(test, false);\n    }\n    \n    /**\n     * <p>\n     * Determines whether the date and (optionally) time of the given Calendar \n     * instance falls on a scheduled fire-time of this trigger.\n     * </p>\n     * \n     * <p>\n     * Note that the value returned is NOT validated against the related\n     * org.quartz.Calendar (if any)\n     * </p>\n     * \n     * @param test the date to compare\n     * @param dayOnly if set to true, the method will only determine if the\n     * trigger will fire during the day represented by the given Calendar\n     * (hours, minutes and seconds will be ignored).\n     * @see #willFireOn(Calendar)\n     */\n    public boolean willFireOn(Calendar test, boolean dayOnly) {\n\n        test = (Calendar) test.clone();\n        \n        test.set(Calendar.MILLISECOND, 0); // don't compare millis.\n        \n        if(dayOnly) {\n            test.set(Calendar.HOUR_OF_DAY, 0); \n            test.set(Calendar.MINUTE, 0); \n            test.set(Calendar.SECOND, 0); \n        }\n        \n        Date testTime = test.getTime();\n        \n        Date fta = getFireTimeAfter(new Date(test.getTime().getTime() - 1000));\n        \n        if(fta == null)\n            return false;\n\n        Calendar p = Calendar.getInstance(test.getTimeZone());\n        p.setTime(fta);\n        \n        int year = p.get(Calendar.YEAR);\n        int month = p.get(Calendar.MONTH);\n        int day = p.get(Calendar.DATE);\n        \n        if(dayOnly) {\n            return (year == test.get(Calendar.YEAR) \n                    && month == test.get(Calendar.MONTH) \n                    && day == test.get(Calendar.DATE));\n        }\n        \n        while(fta.before(testTime)) {\n            fta = getFireTimeAfter(fta);\n        }\n\n        return fta.equals(testTime);\n    }\n\n    /**\n     * <p>\n     * Called when the <code>{@link Scheduler}</code> has decided to 'fire'\n     * the trigger (execute the associated <code>Job</code>), in order to\n     * give the <code>Trigger</code> a chance to update itself for its next\n     * triggering (if any).\n     * </p>\n     * \n     * @see #executionComplete(JobExecutionContext, JobExecutionException)\n     */\n    @Override\n    public void triggered(org.quartz.Calendar calendar) {\n        previousFireTime = nextFireTime;\n        nextFireTime = getFireTimeAfter(nextFireTime);\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            nextFireTime = getFireTimeAfter(nextFireTime);\n        }\n    }\n\n    /**\n     *  \n     * @see AbstractTrigger#updateWithNewCalendar(org.quartz.Calendar, long)\n     */\n    @Override\n    public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold)\n    {\n        nextFireTime = getFireTimeAfter(previousFireTime);\n        \n        if (nextFireTime == null || calendar == null) {\n            return;\n        }\n        \n        Date now = new Date();\n        while (nextFireTime != null && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n\n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            // Use gregorian only because the constant is based on Gregorian\n            java.util.Calendar c = new java.util.GregorianCalendar(); \n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n            \n            if(nextFireTime != null && nextFireTime.before(now)) {\n                long diff = now.getTime() - nextFireTime.getTime();\n                if(diff >= misfireThreshold) {\n                    nextFireTime = getFireTimeAfter(nextFireTime);\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Called by the scheduler at the time a <code>Trigger</code> is first\n     * added to the scheduler, in order to have the <code>Trigger</code>\n     * compute its first fire time, based on any associated calendar.\n     * </p>\n     * \n     * <p>\n     * After this method has been called, <code>getNextFireTime()</code>\n     * should return a valid answer.\n     * </p>\n     * \n     * @return the first time at which the <code>Trigger</code> will be fired\n     *         by the scheduler, which is also the same value <code>getNextFireTime()</code>\n     *         will return (until after the first firing of the <code>Trigger</code>).\n     */\n    @Override\n    public Date computeFirstFireTime(org.quartz.Calendar calendar) {\n        nextFireTime = getFireTimeAfter(new Date(getStartTime().getTime() - 1000L));\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            nextFireTime = getFireTimeAfter(nextFireTime);\n        }\n\n        return nextFireTime;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.CronTriggerI#getExpressionSummary()\n     */\n    public String getExpressionSummary() {\n        return cronEx == null ? null : cronEx.getExpressionSummary();\n    }\n\n    /**\n     * Used by extensions of CronTrigger to imply that there are additional \n     * properties, specifically so that extensions can choose whether to be \n     * stored as a serialized blob, or as a flattened CronTrigger table. \n     */\n    public boolean hasAdditionalProperties() { \n        return false;\n    }\n    /**\n     * Get a {@link ScheduleBuilder} that is configured to produce a \n     * schedule identical to this trigger's schedule.\n     * \n     * @see #getTriggerBuilder()\n     */\n    @Override\n    public ScheduleBuilder<CronTrigger> getScheduleBuilder() {\n        \n        CronScheduleBuilder cb = CronScheduleBuilder.cronSchedule(getCronExpression())\n                .inTimeZone(getTimeZone());\n\n        int misfireInstruction = getMisfireInstruction();\n        switch(misfireInstruction) {\n            case MISFIRE_INSTRUCTION_SMART_POLICY:\n                break;\n            case MISFIRE_INSTRUCTION_DO_NOTHING:\n                cb.withMisfireHandlingInstructionDoNothing();\n                break;\n            case MISFIRE_INSTRUCTION_FIRE_ONCE_NOW:\n                cb.withMisfireHandlingInstructionFireAndProceed();\n                break;\n            case MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY:\n                cb.withMisfireHandlingInstructionIgnoreMisfires();\n                break;\n            default:\n                LOGGER.warn(\"Unrecognized misfire policy {}. Derived builder will use the default cron trigger behavior (MISFIRE_INSTRUCTION_FIRE_ONCE_NOW)\", misfireInstruction);\n        }\n        \n        return cb;\n    }\n    \n    ////////////////////////////////////////////////////////////////////////////\n    //\n    // Computation Functions\n    //\n    ////////////////////////////////////////////////////////////////////////////\n\n    protected Date getTimeAfter(Date afterTime) {\n        return (cronEx == null) ? null : cronEx.getTimeAfter(afterTime);\n    }\n\n    /**\n     * NOT YET IMPLEMENTED: Returns the time before the given time\n     * that this <code>CronTrigger</code> will fire.\n     */ \n    protected Date getTimeBefore(Date eTime) {\n        return (cronEx == null) ? null : cronEx.getTimeBefore(eTime);\n    }\n\n    \n}\n\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/DailyTimeIntervalTriggerImpl.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.triggers;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Set;\n\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\nimport org.quartz.DailyTimeIntervalTrigger;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.TimeOfDay;\nimport org.quartz.Trigger;\nimport org.quartz.DateBuilder.IntervalUnit;\n\n/**\n * A concrete implementation of DailyTimeIntervalTrigger that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * based upon daily repeating time intervals.\n * \n * <p>The trigger will fire every N (see {@link #setRepeatInterval(int)} ) seconds, minutes or hours\n * (see {@link #setRepeatIntervalUnit(org.quartz.DateBuilder.IntervalUnit)}) during a given time window on specified days of the week.</p>\n * \n * <p>For example#1, a trigger can be set to fire every 72 minutes between 8:00 and 11:00 everyday. It's fire times would \n * be 8:00, 9:12, 10:24, then next day would repeat: 8:00, 9:12, 10:24 again.</p>\n * \n * <p>For example#2, a trigger can be set to fire every 23 minutes between 9:20 and 16:47 Monday through Friday.</p>\n * \n * <p>On each day, the starting fire time is reset to startTimeOfDay value, and then it will add repeatInterval value to it until\n * the endTimeOfDay is reached. If you set daysOfWeek values, then fire time will only occur during those week days period. Again,\n * remember this trigger will reset fire time each day with startTimeOfDay, regardless of your interval or endTimeOfDay!</p> \n * \n * <p>The default values for fields if not set are: startTimeOfDay defaults to 00:00:00, the endTimeOfDay default to 23:59:59, \n * and daysOfWeek is default to every day. The startTime default to current time-stamp now, while endTime has not value.</p>\n * \n * <p>If startTime is before startTimeOfDay, then startTimeOfDay will be used and startTime has no affect other than to specify\n * the first day of firing. Else if startTime is \n * after startTimeOfDay, then the first fire time for that day will be the next interval after the startTime. For example, if\n * you set startingTimeOfDay=9am, endingTimeOfDay=11am, interval=15 mins, and startTime=9:33am, then the next fire time will\n * be 9:45pm. Note also that if you do not set startTime value, the trigger builder will default to current time, and current time \n * maybe before or after the startTimeOfDay! So be aware how you set your startTime.</p>\n * \n * <p>This trigger also supports \"repeatCount\" feature to end the trigger fire time after\n * a certain number of count is reached. Just as the SimpleTrigger, setting repeatCount=0 \n * means trigger will fire once only! Setting any positive count then the trigger will repeat \n * count + 1 times. Unlike SimpleTrigger, the default value of repeatCount of this trigger\n * is set to REPEAT_INDEFINITELY instead of 0 though.\n * \n * @see DailyTimeIntervalTrigger\n * @see DailyTimeIntervalScheduleBuilder\n * \n * @since 2.1.0\n * \n * @author James House\n * @author Zemian Deng &lt;saltnlight5@gmail.com&gt;\n */\npublic class DailyTimeIntervalTriggerImpl extends AbstractTrigger<DailyTimeIntervalTrigger> implements DailyTimeIntervalTrigger, CoreTrigger {\n    \n    private static final long serialVersionUID = -632667786771388749L;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    private static final int YEAR_TO_GIVEUP_SCHEDULING_AT = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR) + 100;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    private Date startTime = null;\n\n    private Date endTime = null;\n\n    private Date nextFireTime = null;\n\n    private Date previousFireTime = null;\n    \n    private int repeatCount = REPEAT_INDEFINITELY;\n\n    private  int repeatInterval = 1;\n    \n    private IntervalUnit repeatIntervalUnit = IntervalUnit.MINUTE;\n\n    private Set<Integer> daysOfWeek;\n    \n    private TimeOfDay startTimeOfDay;\n\n    private TimeOfDay endTimeOfDay;\n    \n    private int timesTriggered = 0;\n\n    private boolean complete = false;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> with no settings.\n     * </p>\n     */\n    public DailyTimeIntervalTriggerImpl() {\n        super();\n    }\n\n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> that will occur immediately, and\n     * repeat at the given interval.\n     * </p>\n     * \n     * @param startTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should begin occurring.          \n     * @param endTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should stop occurring.          \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are \n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @throws IllegalArgumentException if an invalid IntervalUnit is given, or the repeat interval is zero or less.\n     */\n    public DailyTimeIntervalTriggerImpl(String name, TimeOfDay startTimeOfDay, TimeOfDay endTimeOfDay, IntervalUnit intervalUnit,  int repeatInterval) {\n        this(name, null, startTimeOfDay, endTimeOfDay, intervalUnit, repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> that will occur immediately, and\n     * repeat at the given interval.\n     * </p>\n     * \n     * @param startTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should begin occurring.          \n     * @param endTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should stop occurring.          \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are \n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @throws IllegalArgumentException if an invalid IntervalUnit is given, or the repeat interval is zero or less.\n     */\n    public DailyTimeIntervalTriggerImpl(String name, String group, TimeOfDay startTimeOfDay, \n            TimeOfDay endTimeOfDay, IntervalUnit intervalUnit, int repeatInterval) {\n        this(name, group, new Date(), null, startTimeOfDay, endTimeOfDay, intervalUnit, repeatInterval);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> that will occur at the given time,\n     * and repeat at the given interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param startTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should begin occurring.          \n     * @param endTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should stop occurring.          \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are\n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * @throws IllegalArgumentException if an invalid IntervalUnit is given, or the repeat interval is zero or less.\n     */\n    public DailyTimeIntervalTriggerImpl(String name, Date startTime,\n            Date endTime, TimeOfDay startTimeOfDay, TimeOfDay endTimeOfDay, \n            IntervalUnit intervalUnit,  int repeatInterval) {\n        this(name, null, startTime, endTime, startTimeOfDay, endTimeOfDay, intervalUnit, repeatInterval);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> that will occur at the given time,\n     * and repeat at the given interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param startTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should begin occurring.          \n     * @param endTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should stop occurring.          \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are \n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * @throws IllegalArgumentException if an invalid IntervalUnit is given, or the repeat interval is zero or less.\n     */\n    public DailyTimeIntervalTriggerImpl(String name, String group, Date startTime,\n            Date endTime, TimeOfDay startTimeOfDay, TimeOfDay endTimeOfDay, \n            IntervalUnit intervalUnit,  int repeatInterval) {\n        super(name, group);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatIntervalUnit(intervalUnit);\n        setRepeatInterval(repeatInterval);\n        setStartTimeOfDay(startTimeOfDay);\n        setEndTimeOfDay(endTimeOfDay);\n    }\n\n    /**\n     * <p>\n     * Create a <code>DailyTimeIntervalTrigger</code> that will occur at the given time,\n     * fire the identified <code>Job</code> and repeat at the given\n     * interval until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param startTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should begin occurring.          \n     * @param endTimeOfDay \n     *          The <code>TimeOfDay</code> that the repeating should stop occurring.          \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are \n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * @throws IllegalArgumentException if an invalid IntervalUnit is given, or the repeat interval is zero or less.\n     */\n    public DailyTimeIntervalTriggerImpl(String name, String group, String jobName,\n            String jobGroup, Date startTime, Date endTime, \n            TimeOfDay startTimeOfDay, TimeOfDay endTimeOfDay,\n            IntervalUnit intervalUnit,  int repeatInterval) {\n        super(name, group, jobName, jobGroup);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatIntervalUnit(intervalUnit);\n        setRepeatInterval(repeatInterval);\n        setStartTimeOfDay(startTimeOfDay);\n        setEndTimeOfDay(endTimeOfDay);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the time at which the <code>DailyTimeIntervalTrigger</code> should occur. It defaults to \n     * the getStartTimeOfDay of current day.\n     * </p>\n     */\n    @Override\n    public Date getStartTime() {\n        if(startTime == null) {\n            startTime = new Date();\n        }\n        return startTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>DailyTimeIntervalTrigger</code> should occur.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if startTime is <code>null</code>.\n     */\n    @Override\n    public void setStartTime(Date startTime) {\n        if (startTime == null) {\n            throw new IllegalArgumentException(\"Start time cannot be null\");\n        }\n\n        Date eTime = getEndTime();\n        if (eTime != null && eTime.before(startTime)) {\n            throw new IllegalArgumentException(\n                \"End time cannot be before start time\");    \n        }\n\n        this.startTime = startTime;\n    }\n\n    /**\n     * <p>\n     * Get the time at which the <code>DailyTimeIntervalTrigger</code> should quit\n     * repeating.\n     * </p>\n     * \n     * @see #getFinalFireTime()\n     */\n    @Override\n    public Date getEndTime() {\n        return endTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>DailyTimeIntervalTrigger</code> should quit\n     * repeating (and be automatically deleted).\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if endTime is before start time.\n     */\n    @Override\n    public void setEndTime(Date endTime) {\n        Date sTime = getStartTime();\n        if (sTime != null && endTime != null && sTime.after(endTime)) {\n            throw new IllegalArgumentException(\n                    \"End time cannot be before start time\");\n        }\n\n        this.endTime = endTime;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.DailyTimeIntervalTriggerI#getRepeatIntervalUnit()\n     */\n    public IntervalUnit getRepeatIntervalUnit() {\n        return repeatIntervalUnit;\n    }\n\n    /**\n     * <p>Set the interval unit - the time unit on with the interval applies.</p>\n     * \n     * @param intervalUnit The repeat interval unit. The only intervals that are valid for this type of trigger are \n     * {@link IntervalUnit#SECOND}, {@link IntervalUnit#MINUTE}, and {@link IntervalUnit#HOUR}.\n     */\n    public void setRepeatIntervalUnit(IntervalUnit intervalUnit) {\n        if (repeatIntervalUnit == null || \n                !((repeatIntervalUnit.equals(IntervalUnit.SECOND) || \n                repeatIntervalUnit.equals(IntervalUnit.MINUTE) || \n                repeatIntervalUnit.equals(IntervalUnit.HOUR))))\n            throw new IllegalArgumentException(\"Invalid repeat IntervalUnit (must be SECOND, MINUTE or HOUR).\");\n        this.repeatIntervalUnit = intervalUnit;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.DailyTimeIntervalTriggerI#getRepeatInterval()\n     */\n    public int getRepeatInterval() {\n        return repeatInterval;\n    }\n\n    /**\n     * <p>\n     * set the time interval that will be added to the <code>DailyTimeIntervalTrigger</code>'s\n     * fire time (in the set repeat interval unit) in order to calculate the time of the \n     * next trigger repeat.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if repeatInterval is &lt; 1\n     */\n    public void setRepeatInterval( int repeatInterval) {\n        if (repeatInterval < 1) {\n            throw new IllegalArgumentException(\n                    \"Repeat interval must be >= 1\");\n        }\n\n        this.repeatInterval = repeatInterval;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.DailyTimeIntervalTriggerI#getTimesTriggered()\n     */\n    public int getTimesTriggered() {\n        return timesTriggered;\n    }\n\n    /**\n     * <p>\n     * Set the number of times the <code>DailyTimeIntervalTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    public void setTimesTriggered(int timesTriggered) {\n        this.timesTriggered = timesTriggered;\n    }\n\n    @Override\n    protected boolean validateMisfireInstruction(int misfireInstruction) {\n        return misfireInstruction >= MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY && misfireInstruction <= MISFIRE_INSTRUCTION_DO_NOTHING;\n\n    }\n\n\n    /**\n     * <p>\n     * Updates the <code>DailyTimeIntervalTrigger</code>'s state based on the\n     * MISFIRE_INSTRUCTION_XXX that was selected when the <code>DailyTimeIntervalTrigger</code>\n     * was created.\n     * </p>\n     * \n     * <p>\n     * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,\n     * then the following scheme will be used: </p>\n     * <ul>\n     * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>\n     * </ul>\n     */\n    @Override\n    public void updateAfterMisfire(org.quartz.Calendar cal) {\n        int instr = getMisfireInstruction();\n\n        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)\n            return;\n\n        if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {\n            instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;\n        }\n\n        if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {\n            Date newFireTime = getFireTimeAfter(new Date());\n            while (newFireTime != null && cal != null\n                    && !cal.isTimeIncluded(newFireTime.getTime())) {\n                newFireTime = getFireTimeAfter(newFireTime);\n            }\n            setNextFireTime(newFireTime);\n        } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { \n            // fire once now...\n            setNextFireTime(new Date());\n            // the new fire time afterward will magically preserve the original  \n            // time of day for firing for day/week/month interval triggers, \n            // because of the way getFireTimeAfter() works - in its always restarting\n            // computation from the start time.\n        }\n    }\n\n    /**\n     * <p>\n     * Called when the <code>{@link Scheduler}</code> has decided to 'fire'\n     * the trigger (execute the associated <code>Job</code>), in order to\n     * give the <code>Trigger</code> a chance to update itself for its next\n     * triggering (if any).\n     * </p>\n     * \n     * @see #executionComplete(JobExecutionContext, JobExecutionException)\n     */\n    @Override\n    public void triggered(org.quartz.Calendar calendar) {\n        timesTriggered++;\n        previousFireTime = nextFireTime;\n        nextFireTime = getFireTimeAfter(nextFireTime);\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            \n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n        }\n        \n        if (nextFireTime == null) {\n            complete = true;\n        }\n    }\n\n\n    /**\n     * @see org.quartz.impl.triggers.AbstractTrigger#updateWithNewCalendar(org.quartz.Calendar, long)\n     */\n    @Override\n    public void updateWithNewCalendar(org.quartz.Calendar calendar, long misfireThreshold)\n    {\n        nextFireTime = getFireTimeAfter(previousFireTime);\n\n        if (nextFireTime == null || calendar == null) {\n            return;\n        }\n        \n        Date now = new Date();\n        while (nextFireTime != null && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n\n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n\n            if(nextFireTime != null && nextFireTime.before(now)) {\n                long diff = now.getTime() - nextFireTime.getTime();\n                if(diff >= misfireThreshold) {\n                    nextFireTime = getFireTimeAfter(nextFireTime);\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Called by the scheduler at the time a <code>Trigger</code> is first\n     * added to the scheduler, in order to have the <code>Trigger</code>\n     * compute its first fire time, based on any associated calendar.\n     * </p>\n     * \n     * <p>\n     * After this method has been called, <code>getNextFireTime()</code>\n     * should return a valid answer.\n     * </p>\n     * \n     * @return the first time at which the <code>Trigger</code> will be fired\n     *         by the scheduler, which is also the same value <code>getNextFireTime()</code>\n     *         will return (until after the first firing of the <code>Trigger</code>).\n     */\n    @Override\n    public Date computeFirstFireTime(org.quartz.Calendar calendar) {\n        \n      nextFireTime = getFireTimeAfter(new Date(getStartTime().getTime() - 1000L));\n      \n      // Check calendar for date-time exclusion\n      while (nextFireTime != null && calendar != null\n              && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n          \n          nextFireTime = getFireTimeAfter(nextFireTime);\n          \n          if(nextFireTime == null)\n              break;\n      \n          //avoid infinite loop\n          java.util.Calendar c = java.util.Calendar.getInstance();\n          c.setTime(nextFireTime);\n          if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n              return null;\n          }\n      }\n      \n      return nextFireTime;\n    }\n    \n    private Calendar createCalendarTime(Date dateTime) {\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(dateTime);\n        return cal;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>Trigger</code> is scheduled to fire. If\n     * the trigger will not fire again, <code>null</code> will be returned.  Note that\n     * the time returned can possibly be in the past, if the time that was computed\n     * for the trigger to next fire has already arrived, but the scheduler has not yet\n     * been able to fire the trigger (which would likely be due to lack of resources\n     * e.g. threads).\n     * </p>\n     *\n     * <p>The value returned is not guaranteed to be valid until after the <code>Trigger</code>\n     * has been added to the scheduler.\n     * </p>\n     */\n    @Override\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the previous time at which the <code>DailyTimeIntervalTrigger</code> \n     * fired. If the trigger has not yet fired, <code>null</code> will be\n     * returned.\n     */\n    @Override\n    public Date getPreviousFireTime() {\n        return previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the next time at which the <code>DailyTimeIntervalTrigger</code> should fire.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setNextFireTime(Date nextFireTime) {\n        this.nextFireTime = nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the previous time at which the <code>DailyTimeIntervalTrigger</code> fired.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setPreviousFireTime(Date previousFireTime) {\n        this.previousFireTime = previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>DailyTimeIntervalTrigger</code> will\n     * fire, after the given time. If the trigger will not fire after the given\n     * time, <code>null</code> will be returned.\n     * </p>\n     */\n    @Override\n    public Date getFireTimeAfter(Date afterTime) {\n        // Check if trigger has completed or not.\n        if (complete) {\n            return null;\n        }\n        \n        // Check repeatCount limit\n        if (repeatCount != REPEAT_INDEFINITELY && timesTriggered > repeatCount) {\n          return null;\n        }\n      \n        // a. Increment afterTime by a second, so that we are comparing against a time after it!\n        if (afterTime == null) {\n          afterTime = new Date(System.currentTimeMillis() + 1000L);\n        } else {\n          afterTime = new Date(afterTime.getTime() + 1000L);\n        }\n         \n        // make sure afterTime is at least startTime\n        if(afterTime.before(startTime))\n          afterTime = startTime;\n\n        // b.Check to see if afterTime is after endTimeOfDay or not. If yes, then we need to advance to next day as well.\n        boolean afterTimePastEndTimeOfDay = false;\n        if (endTimeOfDay != null) {\n          afterTimePastEndTimeOfDay = afterTime.getTime() > endTimeOfDay.getTimeOfDayForDate(afterTime).getTime();\n        }\n        // c. now we need to move to the next valid day of week if either: \n        // the given time is past the end time of day, or given time is not on a valid day of week\n        Date fireTime = advanceToNextDayOfWeekIfNecessary(afterTime, afterTimePastEndTimeOfDay);\n        if (fireTime == null)\n          return null;\n                \n        // d. Calculate and save fireTimeEndDate variable for later use\n        Date fireTimeEndDate;\n        if (endTimeOfDay == null)\n          fireTimeEndDate = new TimeOfDay(23, 59, 59).getTimeOfDayForDate(fireTime);\n        else\n          fireTimeEndDate = endTimeOfDay.getTimeOfDayForDate(fireTime);\n        \n        // e. Check fireTime against startTime or startTimeOfDay to see which go first.\n        Date fireTimeStartDate = startTimeOfDay.getTimeOfDayForDate(fireTime);\n        if (fireTime.before(fireTimeStartDate)) {\n          return fireTimeStartDate;\n        } \n        \n        \n        // f. Continue to calculate the fireTime by incremental unit of intervals.\n        // recall that if fireTime was less that fireTimeStartDate, we didn't get this far\n        long fireMillis = fireTime.getTime();\n        long startMillis = fireTimeStartDate.getTime();\n        long secondsAfterStart = (fireMillis - startMillis) / 1000L;\n        long repeatLong = getRepeatInterval();\n        Calendar sTime = createCalendarTime(fireTimeStartDate);\n        IntervalUnit repeatUnit = getRepeatIntervalUnit();\n        if(repeatUnit.equals(IntervalUnit.SECOND)) {\n            long jumpCount = secondsAfterStart / repeatLong;\n            if(secondsAfterStart % repeatLong != 0)\n                jumpCount++;\n            sTime.add(Calendar.SECOND, getRepeatInterval() * (int)jumpCount);\n            fireTime = sTime.getTime();\n        } else if(repeatUnit.equals(IntervalUnit.MINUTE)) {\n            long jumpCount = secondsAfterStart / (repeatLong * 60L);\n            if(secondsAfterStart % (repeatLong * 60L) != 0)\n                jumpCount++;\n            sTime.add(Calendar.MINUTE, getRepeatInterval() * (int)jumpCount);\n            fireTime = sTime.getTime();\n        } else if(repeatUnit.equals(IntervalUnit.HOUR)) {\n            long jumpCount = secondsAfterStart / (repeatLong * 60L * 60L);\n            if(secondsAfterStart % (repeatLong * 60L * 60L) != 0)\n                jumpCount++;\n            sTime.add(Calendar.HOUR_OF_DAY, getRepeatInterval() * (int)jumpCount);\n            fireTime = sTime.getTime();\n        }\n        \n        // g. Ensure this new fireTime is within the day, or else we need to advance to next day.\n        if (fireTime.after(fireTimeEndDate)) {\n          fireTime = advanceToNextDayOfWeekIfNecessary(fireTime, isSameDay(fireTime, fireTimeEndDate));\n          // make sure we hit the startTimeOfDay on the new day\n          fireTime = startTimeOfDay.getTimeOfDayForDate(fireTime);\n        }\n    \n        // i. Return calculated fireTime.\n        return fireTime;\n    }\n\n    private boolean isSameDay(Date d1, Date d2) {\n    \n      Calendar c1 = createCalendarTime(d1);\n      Calendar c2 = createCalendarTime(d2);\n      \n      return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);\n    }\n    \n    /**\n     * Given fireTime time determine if it is on a valid day of week. If so, simply return it unaltered,\n     * if not, advance to the next valid week day, and set the time of day to the start time of day\n     * \n     * @param fireTime - given next fireTime.\n     * @param forceToAdvanceNextDay - flag to whether to advance day without check existing week day. This scenario\n     * can happen when a caller determine fireTime has passed the endTimeOfDay that fireTime should move to next day anyway.\n     * @return a next day fireTime.\n     */\n    private Date advanceToNextDayOfWeekIfNecessary(Date fireTime, boolean forceToAdvanceNextDay) {\n        // a. Advance or adjust to next dayOfWeek if need to first, starting next day with startTimeOfDay.\n        TimeOfDay sTimeOfDay = getStartTimeOfDay();\n        Date fireTimeStartDate = sTimeOfDay.getTimeOfDayForDate(fireTime);      \n        Calendar fireTimeStartDateCal = createCalendarTime(fireTimeStartDate);          \n        int dayOfWeekOfFireTime = fireTimeStartDateCal.get(Calendar.DAY_OF_WEEK);\n        \n        // b2. We need to advance to another day if isAfterTimePassEndTimeOfDay is true, or dayOfWeek is not set.\n        Set<Integer> daysOfWeekToFire = getDaysOfWeek();\n        if (forceToAdvanceNextDay || !daysOfWeekToFire.contains(dayOfWeekOfFireTime)) {\n          // Advance one day at a time until next available date.\n          for(int i=1; i <= 7; i++) {\n            fireTimeStartDateCal.add(Calendar.DATE, 1);\n            dayOfWeekOfFireTime = fireTimeStartDateCal.get(Calendar.DAY_OF_WEEK);\n            if (daysOfWeekToFire.contains(dayOfWeekOfFireTime)) {\n              fireTime = fireTimeStartDateCal.getTime();\n              break;\n            }\n          }\n        }\n        \n        // Check fireTime not pass the endTime\n         Date eTime = getEndTime();\n         if (eTime != null && fireTime.getTime() > eTime.getTime()) {\n             return null;\n         }\n\n        return fireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the final time at which the <code>DailyTimeIntervalTrigger</code> will\n     * fire, if there is no end time set, null will be returned.\n     * </p>\n     * \n     * <p>\n     * Note that the return time may be in the past.\n     * </p>\n     */\n    @Override\n    public Date getFinalFireTime() {\n        if (complete || getEndTime() == null) {\n            return null;\n        }\n        \n        // We have an endTime, we still need to check to see if there is a endTimeOfDay if that's applicable.\n        Date eTime = getEndTime();\n        if (endTimeOfDay != null) {\n            Date endTimeOfDayDate = endTimeOfDay.getTimeOfDayForDate(eTime);\n            if (eTime.getTime() < endTimeOfDayDate.getTime()) {\n                eTime = endTimeOfDayDate;\n            }\n        }        \n        return eTime;\n    }\n\n    /**\n     * <p>\n     * Determines whether or not the <code>DailyTimeIntervalTrigger</code> will occur\n     * again.\n     * </p>\n     */\n    @Override\n    public boolean mayFireAgain() {\n        return (getNextFireTime() != null);\n    }\n\n    /**\n     * <p>\n     * Validates whether the properties of the <code>JobDetail</code> are\n     * valid for submission into a <code>Scheduler</code>.\n     * \n     * @throws IllegalStateException\n     *           if a required property (such as Name, Group, Class) is not\n     *           set.\n     */\n    @Override\n    public void validate() throws SchedulerException {\n        super.validate();\n        \n        if (repeatIntervalUnit == null || !(repeatIntervalUnit.equals(IntervalUnit.SECOND) || \n                repeatIntervalUnit.equals(IntervalUnit.MINUTE) ||repeatIntervalUnit.equals(IntervalUnit.HOUR)))\n            throw new SchedulerException(\"Invalid repeat IntervalUnit (must be SECOND, MINUTE or HOUR).\");\n        if (repeatInterval < 1) {\n            throw new SchedulerException(\"Repeat Interval cannot be zero.\");\n        }\n        \n        // Ensure interval does not exceed 24 hours\n        long secondsInHour = 24 * 60 * 60L;\n        if (repeatIntervalUnit == IntervalUnit.SECOND && repeatInterval > secondsInHour) {\n            throw new SchedulerException(\"repeatInterval can not exceed 24 hours (\" + secondsInHour + \" seconds). Given \" + repeatInterval);\n        }\n        if (repeatIntervalUnit == IntervalUnit.MINUTE && repeatInterval > secondsInHour / 60L) {\n            throw new SchedulerException(\"repeatInterval can not exceed 24 hours (\" + secondsInHour / 60L + \" minutes). Given \" + repeatInterval);\n        }\n        if (repeatIntervalUnit == IntervalUnit.HOUR && repeatInterval > 24 ) {\n            throw new SchedulerException(\"repeatInterval can not exceed 24 hours. Given \" + repeatInterval + \" hours.\");\n        }        \n        \n        // Ensure timeOfDay is in order.\n        // NOTE: We allow startTimeOfDay to be set equal to endTimeOfDay so the repeatCount can be\n        // set to 1.\n        if (getEndTimeOfDay() != null\n            && !getStartTimeOfDay().equals(getEndTimeOfDay())\n            && !getStartTimeOfDay().before(getEndTimeOfDay())) {\n            throw new SchedulerException(\"StartTimeOfDay \" + startTimeOfDay\n                + \" should not come after endTimeOfDay \" + endTimeOfDay);\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public Set<Integer> getDaysOfWeek() {\n        if (daysOfWeek == null) {\n            daysOfWeek = DailyTimeIntervalScheduleBuilder.ALL_DAYS_OF_THE_WEEK;\n        }\n        return daysOfWeek;\n    }\n\n    public void setDaysOfWeek(Set<Integer> daysOfWeek) {\n        if(daysOfWeek == null || daysOfWeek.isEmpty())\n            throw new IllegalArgumentException(\"DaysOfWeek set must be a set that contains at least one day.\");\n\n        this.daysOfWeek = daysOfWeek;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public TimeOfDay getStartTimeOfDay() {\n        if (startTimeOfDay == null) {\n            startTimeOfDay = new TimeOfDay(0, 0, 0);\n        }\n        return startTimeOfDay;\n    }\n\n    public void setStartTimeOfDay(TimeOfDay startTimeOfDay) {\n        if (startTimeOfDay == null) {\n            throw new IllegalArgumentException(\"Start time of day cannot be null\");\n        }\n\n        TimeOfDay eTime = getEndTimeOfDay();\n        if (eTime != null && eTime.before(startTimeOfDay)) {\n            throw new IllegalArgumentException(\n                \"End time of day cannot be before start time of day\");    \n        }\n\n        this.startTimeOfDay = startTimeOfDay;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public TimeOfDay getEndTimeOfDay() {\n        return endTimeOfDay;\n    }\n\n    public void setEndTimeOfDay(TimeOfDay endTimeOfDay) {\n        if (endTimeOfDay == null) \n            throw new IllegalArgumentException(\"End time of day cannot be null\");\n\n        TimeOfDay sTime = getStartTimeOfDay();\n        if (sTime != null && endTimeOfDay.before(endTimeOfDay)) {\n            throw new IllegalArgumentException(\n                    \"End time of day cannot be before start time of day\");\n        }\n        this.endTimeOfDay = endTimeOfDay;\n    }\n    \n    /**\n     * Get a {@link ScheduleBuilder} that is configured to produce a \n     * schedule identical to this trigger's schedule.\n     * \n     * @see #getTriggerBuilder()\n     */\n    @Override\n    public ScheduleBuilder<DailyTimeIntervalTrigger> getScheduleBuilder() {\n        \n        DailyTimeIntervalScheduleBuilder cb = DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n                .withInterval(getRepeatInterval(), getRepeatIntervalUnit())\n                .onDaysOfTheWeek(getDaysOfWeek()).startingDailyAt(getStartTimeOfDay()).endingDailyAt(getEndTimeOfDay());\n            \n        switch(getMisfireInstruction()) {\n            case MISFIRE_INSTRUCTION_DO_NOTHING : cb.withMisfireHandlingInstructionDoNothing();\n            break;\n            case MISFIRE_INSTRUCTION_FIRE_ONCE_NOW : cb.withMisfireHandlingInstructionFireAndProceed();\n            break;\n        }\n        \n        return cb;\n    }\n\n    /** This trigger has no additional properties besides what's defined in this class. */\n    public boolean hasAdditionalProperties() {\n        return false;\n    }\n    \n    public int getRepeatCount() {\n        return repeatCount;\n    }\n    \n    public void setRepeatCount(int repeatCount) {\n        if (repeatCount < 0 && repeatCount != REPEAT_INDEFINITELY) {\n            throw new IllegalArgumentException(\"Repeat count must be >= 0, use the \" +\n                    \"constant REPEAT_INDEFINITELY for infinite.\");\n        }\n\n        this.repeatCount = repeatCount;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/SimpleTriggerImpl.java",
    "content": "\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.impl.triggers;\n\nimport java.util.Date;\n\nimport org.quartz.Calendar;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerUtils;\n\n\n/**\n * <p>\n * A concrete <code>{@link Trigger}</code> that is used to fire a <code>{@link org.quartz.JobDetail}</code>\n * at a given moment in time, and optionally repeated at a specified interval.\n * </p>\n * \n * @see Trigger\n * @see CronTrigger\n * @see TriggerUtils\n * \n * @author James House\n * @author contributions by Lieven Govaerts of Ebitec Nv, Belgium.\n */\npublic class SimpleTriggerImpl extends AbstractTrigger<SimpleTrigger> implements SimpleTrigger, CoreTrigger {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Required for serialization support. Introduced in Quartz 1.6.1 to \n     * maintain compatibility after the introduction of hasAdditionalProperties\n     * method. \n     * \n     * @see java.io.Serializable\n     */\n    private static final long serialVersionUID = -3735980074222850397L;\n\n    private static final int YEAR_TO_GIVEUP_SCHEDULING_AT = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR) + 100;\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    private Date startTime = null;\n\n    private Date endTime = null;\n\n    private Date nextFireTime = null;\n\n    private Date previousFireTime = null;\n\n    private int repeatCount = 0;\n\n    private long repeatInterval = 0;\n\n    private int timesTriggered = 0;\n\n    private final boolean complete = false;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> with no settings.\n     * </p>\n     */\n    public SimpleTriggerImpl() {\n        super();\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur immediately, and\n     * not repeat.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name) {\n        this(name, (String)null);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur immediately, and\n     * not repeat.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, String group) {\n        this(name, group, new Date(), null, 0, 0);\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur immediately, and\n     * repeat at the given interval the given number of times.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, int repeatCount, long repeatInterval) {\n        this(name, null, repeatCount, repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur immediately, and\n     * repeat at the given interval the given number of times.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, String group, int repeatCount,\n            long repeatInterval) {\n        this(name, group, new Date(), null, repeatCount, repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur at the given time,\n     * and not repeat.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, Date startTime) {\n        this(name, null, startTime);\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur at the given time,\n     * and not repeat.\n     * </p>\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, String group, Date startTime) {\n        this(name, group, startTime, null, 0, 0);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur at the given time,\n     * and repeat at the given interval the given number of times, or until\n     * the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param repeatCount\n     *          The number of times for the <code>Trigger</code> to repeat\n     *          firing, use {@link #REPEAT_INDEFINITELY} for unlimited times.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, Date startTime,\n            Date endTime, int repeatCount, long repeatInterval) {\n        this(name, null, startTime, endTime, repeatCount, repeatInterval);\n    }\n    \n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur at the given time,\n     * and repeat at the given interval the given number of times, or until\n     * the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param repeatCount\n     *          The number of times for the <code>Trigger</code> to repeat\n     *          firing, use {@link #REPEAT_INDEFINITELY} for unlimited times.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, String group, Date startTime,\n            Date endTime, int repeatCount, long repeatInterval) {\n        super(name, group);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatCount(repeatCount);\n        setRepeatInterval(repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Create a <code>SimpleTrigger</code> that will occur at the given time,\n     * fire the identified <code>Job</code> and repeat at the given\n     * interval the given number of times, or until the given end time.\n     * </p>\n     * \n     * @param startTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to fire.\n     * @param endTime\n     *          A <code>Date</code> set to the time for the <code>Trigger</code>\n     *          to quit repeat firing.\n     * @param repeatCount\n     *          The number of times for the <code>Trigger</code> to repeat\n     *          firing, use {@link #REPEAT_INDEFINITELY}for unlimited times.\n     * @param repeatInterval\n     *          The number of milliseconds to pause between the repeat firing.\n     * \n     * @deprecated use a TriggerBuilder instead\n     */\n    @Deprecated\n    public SimpleTriggerImpl(String name, String group, String jobName,\n            String jobGroup, Date startTime, Date endTime, int repeatCount,\n            long repeatInterval) {\n        super(name, group, jobName, jobGroup);\n\n        setStartTime(startTime);\n        setEndTime(endTime);\n        setRepeatCount(repeatCount);\n        setRepeatInterval(repeatInterval);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the time at which the <code>SimpleTrigger</code> should occur.\n     * </p>\n     */\n    @Override\n    public Date getStartTime() {\n        return startTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>SimpleTrigger</code> should occur.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if startTime is <code>null</code>.\n     */\n    @Override\n    public void setStartTime(Date startTime) {\n        if (startTime == null) {\n            throw new IllegalArgumentException(\"Start time cannot be null\");\n        }\n\n        Date eTime = getEndTime();\n        if (eTime != null && eTime.before(startTime)) {\n            throw new IllegalArgumentException(\n                \"End time cannot be before start time\");    \n        }\n\n        this.startTime = startTime;\n    }\n\n    /**\n     * <p>\n     * Get the time at which the <code>SimpleTrigger</code> should quit\n     * repeating - even if repeatCount isn't yet satisfied.\n     * </p>\n     * \n     * @see #getFinalFireTime()\n     */\n    @Override\n    public Date getEndTime() {\n        return endTime;\n    }\n\n    /**\n     * <p>\n     * Set the time at which the <code>SimpleTrigger</code> should quit\n     * repeating (and be automatically deleted).\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if endTime is before start time.\n     */\n    @Override\n    public void setEndTime(Date endTime) {\n        Date sTime = getStartTime();\n        if (sTime != null && endTime != null && sTime.after(endTime)) {\n            throw new IllegalArgumentException(\n                    \"End time cannot be before start time\");\n        }\n\n        this.endTime = endTime;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.SimpleTriggerI#getRepeatCount()\n     */\n    public int getRepeatCount() {\n        return repeatCount;\n    }\n\n    /**\n     * <p>\n     * Set the number of time the <code>SimpleTrigger</code> should\n     * repeat, after which it will be automatically deleted.\n     * </p>\n     * \n     * @see #REPEAT_INDEFINITELY\n     * @exception IllegalArgumentException\n     *              if repeatCount is &lt; 0\n     */\n    public void setRepeatCount(int repeatCount) {\n        if (repeatCount < 0 && repeatCount != REPEAT_INDEFINITELY) {\n            throw new IllegalArgumentException(\n                    \"Repeat count must be >= 0, use the \"\n                            + \"constant REPEAT_INDEFINITELY for infinite.\");\n        }\n\n        this.repeatCount = repeatCount;\n    }\n\n    /* (non-Javadoc)\n     * @see org.quartz.SimpleTriggerI#getRepeatInterval()\n     */\n    public long getRepeatInterval() {\n        return repeatInterval;\n    }\n\n    /**\n     * <p>\n     * Set the time interval (in milliseconds) at which the <code>SimpleTrigger</code>\n     * should repeat.\n     * </p>\n     * \n     * @exception IllegalArgumentException\n     *              if repeatInterval is &lt; 0\n     */\n    public void setRepeatInterval(long repeatInterval) {\n        if (repeatInterval < 0) {\n            throw new IllegalArgumentException(\n                    \"Repeat interval must be >= 0\");\n        }\n\n        this.repeatInterval = repeatInterval;\n    }\n\n    /**\n     * <p>\n     * Get the number of times the <code>SimpleTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    public int getTimesTriggered() {\n        return timesTriggered;\n    }\n\n    /**\n     * <p>\n     * Set the number of times the <code>SimpleTrigger</code> has already\n     * fired.\n     * </p>\n     */\n    public void setTimesTriggered(int timesTriggered) {\n        this.timesTriggered = timesTriggered;\n    }\n\n    @Override\n    protected boolean validateMisfireInstruction(int misfireInstruction) {\n        if (misfireInstruction < MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {\n            return false;\n        }\n\n        return misfireInstruction <= MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT;\n    }\n\n    /**\n     * <p>\n     * Updates the <code>SimpleTrigger</code>'s state based on the\n     * MISFIRE_INSTRUCTION_XXX that was selected when the <code>SimpleTrigger</code>\n     * was created.\n     * </p>\n     * \n     * <p>\n     * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,\n     * then the following scheme will be used: </p>\n     * <ul>\n     * <li>If the Repeat Count is <code>0</code>, then the instruction will\n     * be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_NOW</code>.</li>\n     * <li>If the Repeat Count is <code>REPEAT_INDEFINITELY</code>, then\n     * the instruction will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT</code>.\n     * <b>WARNING:</b> using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT \n     * with a trigger that has a non-null end-time may cause the trigger to \n     * never fire again if the end-time arrived during the misfire time span. \n     * </li>\n     * <li>If the Repeat Count is <code>&gt; 0</code>, then the instruction\n     * will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>.\n     * </li>\n     * </ul>\n     */\n    @Override\n    public void updateAfterMisfire(Calendar cal) {\n        int instr = getMisfireInstruction();\n        \n        if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)\n            return;\n        \n        if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) {\n            if (getRepeatCount() == 0) {\n                instr = MISFIRE_INSTRUCTION_FIRE_NOW;\n            } else if (getRepeatCount() == REPEAT_INDEFINITELY) {\n                instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;\n            } else {\n                // if (getRepeatCount() > 0)\n                instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;\n            }\n        } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) {\n            instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;\n        }\n\n        if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) {\n            setNextFireTime(new Date());\n        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {\n            Date newFireTime = getFireTimeAfter(new Date());\n            while (newFireTime != null && cal != null\n                    && !cal.isTimeIncluded(newFireTime.getTime())) {\n                newFireTime = getFireTimeAfter(newFireTime);\n\n                if(newFireTime == null)\n                    break;\n                \n                //avoid infinite loop\n                java.util.Calendar c = java.util.Calendar.getInstance();\n                c.setTime(newFireTime);\n                if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                    newFireTime = null;\n                }\n            }\n            setNextFireTime(newFireTime);\n        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {\n            Date newFireTime = getFireTimeAfter(new Date());\n            while (newFireTime != null && cal != null\n                    && !cal.isTimeIncluded(newFireTime.getTime())) {\n                newFireTime = getFireTimeAfter(newFireTime);\n\n                if(newFireTime == null)\n                    break;\n                \n                //avoid infinite loop\n                java.util.Calendar c = java.util.Calendar.getInstance();\n                c.setTime(newFireTime);\n                if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                    newFireTime = null;\n                }\n            }\n            if (newFireTime != null) {\n                int timesMissed = computeNumTimesFiredBetween(nextFireTime,\n                        newFireTime);\n                setTimesTriggered(getTimesTriggered() + timesMissed);\n            }\n\n            setNextFireTime(newFireTime);\n        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) {\n            Date newFireTime = new Date();\n            if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {\n                setRepeatCount(getRepeatCount() - getTimesTriggered());\n                setTimesTriggered(0);\n            }\n            \n            if (getEndTime() != null && getEndTime().before(newFireTime)) {\n                setNextFireTime(null); // We are past the end time\n            } else {\n                setStartTime(newFireTime);\n                setNextFireTime(newFireTime);\n            } \n        } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) {\n            Date newFireTime = new Date();\n\n            int timesMissed = computeNumTimesFiredBetween(nextFireTime,\n                    newFireTime);\n\n            if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {\n                int remainingCount = getRepeatCount()\n                        - (getTimesTriggered() + timesMissed);\n                if (remainingCount <= 0) { \n                    remainingCount = 0;\n                }\n                setRepeatCount(remainingCount);\n                setTimesTriggered(0);\n            }\n\n            if (getEndTime() != null && getEndTime().before(newFireTime)) {\n                setNextFireTime(null); // We are past the end time\n            } else {\n                setStartTime(newFireTime);\n                setNextFireTime(newFireTime);\n            } \n        }\n\n    }\n\n    /**\n     * <p>\n     * Called when the <code>{@link Scheduler}</code> has decided to 'fire'\n     * the trigger (execute the associated <code>Job</code>), in order to\n     * give the <code>Trigger</code> a chance to update itself for its next\n     * triggering (if any).\n     * </p>\n     * \n     * @see #executionComplete(JobExecutionContext, JobExecutionException)\n     */\n    @Override\n    public void triggered(Calendar calendar) {\n        timesTriggered++;\n        previousFireTime = nextFireTime;\n        nextFireTime = getFireTimeAfter(nextFireTime);\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            \n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n        }\n    }\n\n    /**\n     * @see org.quartz.impl.triggers.AbstractTrigger#updateWithNewCalendar(org.quartz.Calendar, long)\n     */\n    @Override\n    public void updateWithNewCalendar(Calendar calendar, long misfireThreshold)\n    {\n        nextFireTime = getFireTimeAfter(previousFireTime);\n\n        if (nextFireTime == null || calendar == null) {\n            return;\n        }\n        \n        Date now = new Date();\n        while (nextFireTime != null && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n\n            nextFireTime = getFireTimeAfter(nextFireTime);\n\n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                nextFireTime = null;\n            }\n\n            if(nextFireTime != null && nextFireTime.before(now)) {\n                long diff = now.getTime() - nextFireTime.getTime();\n                if(diff >= misfireThreshold) {\n                    nextFireTime = getFireTimeAfter(nextFireTime);\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Called by the scheduler at the time a <code>Trigger</code> is first\n     * added to the scheduler, in order to have the <code>Trigger</code>\n     * compute its first fire time, based on any associated calendar.\n     * </p>\n     * \n     * <p>\n     * After this method has been called, <code>getNextFireTime()</code>\n     * should return a valid answer.\n     * </p>\n     * \n     * @return the first time at which the <code>Trigger</code> will be fired\n     *         by the scheduler, which is also the same value <code>getNextFireTime()</code>\n     *         will return (until after the first firing of the <code>Trigger</code>).\n     */\n    @Override\n    public Date computeFirstFireTime(Calendar calendar) {\n        nextFireTime = getStartTime();\n\n        while (nextFireTime != null && calendar != null\n                && !calendar.isTimeIncluded(nextFireTime.getTime())) {\n            nextFireTime = getFireTimeAfter(nextFireTime);\n            \n            if(nextFireTime == null)\n                break;\n            \n            //avoid infinite loop\n            java.util.Calendar c = java.util.Calendar.getInstance();\n            c.setTime(nextFireTime);\n            if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {\n                return null;\n            }\n        }\n        \n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>Trigger</code> is scheduled to fire. If\n     * the trigger will not fire again, <code>null</code> will be returned.  Note that\n     * the time returned can possibly be in the past, if the time that was computed\n     * for the trigger to next fire has already arrived, but the scheduler has not yet\n     * been able to fire the trigger (which would likely be due to lack of resources\n     * e.g. threads).\n     * </p>\n     *\n     * <p>The value returned is not guaranteed to be valid until after the <code>Trigger</code>\n     * has been added to the scheduler.\n     * </p>\n     *\n     * @see TriggerUtils#computeFireTimesBetween(org.quartz.spi.OperableTrigger, org.quartz.Calendar, java.util.Date, java.util.Date)\n     */\n    @Override\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the previous time at which the <code>SimpleTrigger</code> \n     * fired. If the trigger has not yet fired, <code>null</code> will be\n     * returned.\n     */\n    @Override\n    public Date getPreviousFireTime() {\n        return previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the next time at which the <code>SimpleTrigger</code> should fire.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setNextFireTime(Date nextFireTime) {\n        this.nextFireTime = nextFireTime;\n    }\n\n    /**\n     * <p>\n     * Set the previous time at which the <code>SimpleTrigger</code> fired.\n     * </p>\n     * \n     * <p>\n     * <b>This method should not be invoked by client code.</b>\n     * </p>\n     */\n    public void setPreviousFireTime(Date previousFireTime) {\n        this.previousFireTime = previousFireTime;\n    }\n\n    /**\n     * <p>\n     * Returns the next time at which the <code>SimpleTrigger</code> will\n     * fire, after the given time. If the trigger will not fire after the given\n     * time, <code>null</code> will be returned.\n     * </p>\n     */\n    @Override\n    public Date getFireTimeAfter(Date afterTime) {\n        if (complete) {\n            return null;\n        }\n\n        if ((timesTriggered > repeatCount)\n                && (repeatCount != REPEAT_INDEFINITELY)) {\n            return null;\n        }\n\n        if (afterTime == null) {\n            afterTime = new Date();\n        }\n\n        if (repeatCount == 0 && afterTime.compareTo(getStartTime()) >= 0) {\n            return null;\n        }\n\n        long startMillis = getStartTime().getTime();\n        long afterMillis = afterTime.getTime();\n        long endMillis = (getEndTime() == null) ? Long.MAX_VALUE : getEndTime()\n                .getTime();\n\n        if (endMillis <= afterMillis) {\n            return null;\n        }\n\n        if (afterMillis < startMillis) {\n            return new Date(startMillis);\n        }\n\n        long numberOfTimesExecuted = ((afterMillis - startMillis) / repeatInterval) + 1;\n\n        if ((numberOfTimesExecuted > repeatCount) && \n            (repeatCount != REPEAT_INDEFINITELY)) {\n            return null;\n        }\n\n        Date time = new Date(startMillis + (numberOfTimesExecuted * repeatInterval));\n\n        if (endMillis <= time.getTime()) {\n            return null;\n        }\n\n        return time;\n    }\n\n    /**\n     * <p>\n     * Returns the last time at which the <code>SimpleTrigger</code> will\n     * fire, before the given time. If the trigger will not fire before the\n     * given time, <code>null</code> will be returned.\n     * </p>\n     */\n    public Date getFireTimeBefore(Date end) {\n        if (end.getTime() < getStartTime().getTime()) {\n            return null;\n        }\n\n        int numFires = computeNumTimesFiredBetween(getStartTime(), end);\n\n        return new Date(getStartTime().getTime() + (numFires * repeatInterval));\n    }\n\n    public int computeNumTimesFiredBetween(Date start, Date end) {\n\n        if(repeatInterval < 1) {\n            return 0;\n        }\n        \n        long time = end.getTime() - start.getTime();\n\n        return (int) (time / repeatInterval);\n    }\n\n    /**\n     * <p>\n     * Returns the final time at which the <code>SimpleTrigger</code> will\n     * fire, if repeatCount is REPEAT_INDEFINITELY, null will be returned.\n     * </p>\n     * \n     * <p>\n     * Note that the return time may be in the past.\n     * </p>\n     */\n    @Override\n    public Date getFinalFireTime() {\n        if (repeatCount == 0) {\n            return startTime;\n        }\n\n        if (repeatCount == REPEAT_INDEFINITELY) {\n            return (getEndTime() == null) ? null : getFireTimeBefore(getEndTime()); \n        }\n\n        long lastTrigger = startTime.getTime() + (repeatCount * repeatInterval);\n\n        if ((getEndTime() == null) || (lastTrigger < getEndTime().getTime())) { \n            return new Date(lastTrigger);\n        } else {\n            return getFireTimeBefore(getEndTime());\n        }\n    }\n\n    /**\n     * <p>\n     * Determines whether or not the <code>SimpleTrigger</code> will occur\n     * again.\n     * </p>\n     */\n    @Override\n    public boolean mayFireAgain() {\n        return (getNextFireTime() != null);\n    }\n\n    /**\n     * <p>\n     * Validates whether the properties of the <code>JobDetail</code> are\n     * valid for submission into a <code>Scheduler</code>.\n     * \n     * @throws IllegalStateException\n     *           if a required property (such as Name, Group, Class) is not\n     *           set.\n     */\n    @Override\n    public void validate() throws SchedulerException {\n        super.validate();\n\n        if (repeatCount != 0 && repeatInterval < 1) {\n            throw new SchedulerException(\"Repeat Interval cannot be zero.\");\n        }\n    }\n\n    /**\n     * Used by extensions of SimpleTrigger to imply that there are additional \n     * properties, specifically so that extensions can choose whether to be \n     * stored as a serialized blob, or as a flattened SimpleTrigger table. \n     */\n    public boolean hasAdditionalProperties() {\n        return false;\n    }\n\n    /**\n     * Get a {@link ScheduleBuilder} that is configured to produce a \n     * schedule identical to this trigger's schedule.\n     * \n     * @see #getTriggerBuilder()\n     */\n    @Override\n    public ScheduleBuilder<SimpleTrigger> getScheduleBuilder() {\n        \n        SimpleScheduleBuilder sb = SimpleScheduleBuilder.simpleSchedule()\n        .withIntervalInMilliseconds(getRepeatInterval())\n        .withRepeatCount(getRepeatCount());\n        \n        switch(getMisfireInstruction()) {\n            case MISFIRE_INSTRUCTION_FIRE_NOW : sb.withMisfireHandlingInstructionFireNow();\n            break;\n            case MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT : sb.withMisfireHandlingInstructionNextWithExistingCount();\n            break;\n            case MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT : sb.withMisfireHandlingInstructionNextWithRemainingCount();\n            break;\n            case MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT : sb.withMisfireHandlingInstructionNowWithExistingCount();\n            break;\n            case MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT : sb.withMisfireHandlingInstructionNowWithRemainingCount();\n            break;\n        }\n        \n        return sb;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/impl/triggers/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.triggers</title>\n</head>\n<body>\n<p>This package contains Trigger implementations that ship with Quartz.  End-users should not directly use these classes,\nbut rather use the builders and interfaces found in the main org.quartz package.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project for more information.\n\n</body>\n</html>"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/BroadcastJobListener.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.listeners;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobListener;\n\n/**\n * Holds a List of references to JobListener instances and broadcasts all\n * events to them (in order).\n *\n * <p>The broadcasting behavior of this listener to delegate listeners may be\n * more convenient than registering all of the listeners directly with the\n * Scheduler, and provides the flexibility of easily changing which listeners\n * get notified.</p>\n *\n *\n * @see #addListener(org.quartz.JobListener)\n * @see #removeListener(org.quartz.JobListener)\n * @see #removeListener(String)\n *\n * @author James House (jhouse AT revolition DOT net)\n */\npublic class BroadcastJobListener implements JobListener {\n\n    private final String name;\n    private final List<JobListener> listeners;\n\n    /**\n     * Construct an instance with the given name.\n     *\n     * (Remember to add some delegate listeners!)\n     *\n     * @param name the name of this instance\n     */\n    public BroadcastJobListener(String name) {\n        if(name == null) {\n            throw new IllegalArgumentException(\"Listener name cannot be null!\");\n        }\n        this.name = name;\n        listeners = new LinkedList<>();\n    }\n\n    /**\n     * Construct an instance with the given name, and List of listeners.\n     *\n     * @param name the name of this instance\n     * @param listeners the initial List of JobListeners to broadcast to.\n     */\n    public BroadcastJobListener(String name, List<JobListener> listeners) {\n        this(name);\n        this.listeners.addAll(listeners);\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void addListener(JobListener listener) {\n        listeners.add(listener);\n    }\n\n    public boolean removeListener(JobListener listener) {\n        return listeners.remove(listener);\n    }\n\n    public boolean removeListener(String listenerName) {\n        Iterator<JobListener> itr = listeners.iterator();\n        while(itr.hasNext()) {\n            JobListener jl = itr.next();\n            if(jl.getName().equals(listenerName)) {\n                itr.remove();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public List<JobListener> getListeners() {\n        return java.util.Collections.unmodifiableList(listeners);\n    }\n\n    public void jobToBeExecuted(JobExecutionContext context) {\n\n        for (JobListener jl : listeners) {\n            jl.jobToBeExecuted(context);\n        }\n    }\n\n    public void jobExecutionVetoed(JobExecutionContext context) {\n\n        for (JobListener jl : listeners) {\n            jl.jobExecutionVetoed(context);\n        }\n    }\n\n    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {\n\n        for (JobListener jl : listeners) {\n            jl.jobWasExecuted(context, jobException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/BroadcastSchedulerListener.java",
    "content": "package org.quartz.listeners;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerListener;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\n\n/**\n * Holds a List of references to SchedulerListener instances and broadcasts all\n * events to them (in order).\n *\n * <p>This may be more convenient than registering all of the listeners\n * directly with the Scheduler, and provides the flexibility of easily changing\n * which listeners get notified.</p>\n *\n * @see #addListener(org.quartz.SchedulerListener)\n * @see #removeListener(org.quartz.SchedulerListener)\n *\n * @author James House (jhouse AT revolition DOT net)\n */\npublic class BroadcastSchedulerListener implements SchedulerListener {\n\n    private final List<SchedulerListener> listeners;\n\n    public BroadcastSchedulerListener() {\n        listeners = new LinkedList<>();\n    }\n\n    /**\n     * Construct an instance with the given List of listeners.\n     *\n     * @param listeners the initial List of SchedulerListeners to broadcast to.\n     */\n    public BroadcastSchedulerListener(List<SchedulerListener> listeners) {\n        this();\n        this.listeners.addAll(listeners);\n    }\n\n\n    public void addListener(SchedulerListener listener) {\n        listeners.add(listener);\n    }\n\n    public boolean removeListener(SchedulerListener listener) {\n        return listeners.remove(listener);\n    }\n\n    public List<SchedulerListener> getListeners() {\n        return java.util.Collections.unmodifiableList(listeners);\n    }\n\n    public void jobAdded(JobDetail jobDetail) {\n        for (SchedulerListener l : listeners) {\n            l.jobAdded(jobDetail);\n        }\n    }\n\n    public void jobDeleted(JobKey jobKey) {\n        for (SchedulerListener l : listeners) {\n            l.jobDeleted(jobKey);\n        }\n    }\n    \n    public void jobScheduled(Trigger trigger) {\n        for (SchedulerListener l : listeners) {\n            l.jobScheduled(trigger);\n        }\n    }\n\n    public void jobUnscheduled(TriggerKey triggerKey) {\n        for (SchedulerListener l : listeners) {\n            l.jobUnscheduled(triggerKey);\n        }\n    }\n\n    public void triggerFinalized(Trigger trigger) {\n        for (SchedulerListener l : listeners) {\n            l.triggerFinalized(trigger);\n        }\n    }\n\n    public void triggerPaused(TriggerKey key) {\n        for (SchedulerListener l : listeners) {\n            l.triggerPaused(key);\n        }\n    }\n\n    public void triggersPaused(String triggerGroup) {\n        for (SchedulerListener l : listeners) {\n            l.triggersPaused(triggerGroup);\n        }\n    }\n\n    public void triggerResumed(TriggerKey key) {\n        for (SchedulerListener l : listeners) {\n            l.triggerResumed(key);\n        }\n    }\n\n    public void triggersResumed(String triggerGroup) {\n        for (SchedulerListener l : listeners) {\n            l.triggersResumed(triggerGroup);\n        }\n    }\n    \n    public void schedulingDataCleared() {\n        for (SchedulerListener l : listeners) {\n            l.schedulingDataCleared();\n        }\n    }\n\n    \n    public void jobPaused(JobKey key) {\n        for (SchedulerListener l : listeners) {\n            l.jobPaused(key);\n        }\n    }\n\n    public void jobsPaused(String jobGroup) {\n        for (SchedulerListener l : listeners) {\n            l.jobsPaused(jobGroup);\n        }\n    }\n\n    public void jobResumed(JobKey key) {\n        for (SchedulerListener l : listeners) {\n            l.jobResumed(key);\n        }\n    }\n\n    public void jobsResumed(String jobGroup) {\n        for (SchedulerListener l : listeners) {\n            l.jobsResumed(jobGroup);\n        }\n    }\n    \n    public void schedulerError(String msg, SchedulerException cause) {\n        for (SchedulerListener l : listeners) {\n            l.schedulerError(msg, cause);\n        }\n    }\n\n    public void schedulerStarted() {\n        for (SchedulerListener l : listeners) {\n            l.schedulerStarted();\n        }\n    }\n    \n    public void schedulerStarting() {\n        for (SchedulerListener l : listeners) {\n            l.schedulerStarting();\n        }\n    }\n\n    public void schedulerInStandbyMode() {\n        for (SchedulerListener l : listeners) {\n            l.schedulerInStandbyMode();\n        }\n    }\n    \n    public void schedulerShutdown() {\n        for (SchedulerListener l : listeners) {\n            l.schedulerShutdown();\n        }\n    }\n    \n    public void schedulerShuttingdown() {\n        for (SchedulerListener l : listeners) {\n            l.schedulerShuttingdown();\n        }\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/BroadcastTriggerListener.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.listeners;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerListener;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\n\n/**\n * Holds a List of references to TriggerListener instances and broadcasts all\n * events to them (in order).\n *\n * <p>The broadcasting behavior of this listener to delegate listeners may be\n * more convenient than registering all of the listeners directly with the\n * Scheduler, and provides the flexibility of easily changing which listeners\n * get notified.</p>\n *\n * @see #addListener(org.quartz.TriggerListener)\n * @see #removeListener(org.quartz.TriggerListener)\n * @see #removeListener(String)\n *\n * @author James House (jhouse AT revolition DOT net)\n */\npublic class BroadcastTriggerListener implements TriggerListener {\n\n    private final String name;\n    private final List<TriggerListener> listeners;\n\n    /**\n     * Construct an instance with the given name.\n     *\n     * (Remember to add some delegate listeners!)\n     *\n     * @param name the name of this instance\n     */\n    public BroadcastTriggerListener(String name) {\n        if(name == null) {\n            throw new IllegalArgumentException(\"Listener name cannot be null!\");\n        }\n        this.name = name;\n        listeners = new LinkedList<>();\n    }\n\n    /**\n     * Construct an instance with the given name, and List of listeners.\n     *\n     * @param name the name of this instance\n     * @param listeners the initial List of TriggerListeners to broadcast to.\n     */\n    public BroadcastTriggerListener(String name, List<TriggerListener> listeners) {\n        this(name);\n        this.listeners.addAll(listeners);\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void addListener(TriggerListener listener) {\n        listeners.add(listener);\n    }\n\n    public boolean removeListener(TriggerListener listener) {\n        return listeners.remove(listener);\n    }\n\n    public boolean removeListener(String listenerName) {\n        Iterator<TriggerListener> itr = listeners.iterator();\n        while(itr.hasNext()) {\n            TriggerListener l = itr.next();\n            if(l.getName().equals(listenerName)) {\n                itr.remove();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public List<TriggerListener> getListeners() {\n        return java.util.Collections.unmodifiableList(listeners);\n    }\n\n    public void triggerFired(Trigger trigger, JobExecutionContext context) {\n\n        for (TriggerListener l : listeners) {\n            l.triggerFired(trigger, context);\n        }\n    }\n\n    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {\n\n        for (TriggerListener l : listeners) {\n            if (l.vetoJobExecution(trigger, context)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public void triggerMisfired(Trigger trigger) {\n\n        for (TriggerListener l : listeners) {\n            l.triggerMisfired(trigger);\n        }\n    }\n\n    public void triggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode) {\n\n        for (TriggerListener l : listeners) {\n            l.triggerComplete(trigger, context, triggerInstructionCode);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/JobChainingJobListener.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.listeners;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerException;\n\n/**\n * Keeps a collection of mappings of which Job to trigger after the completion\n * of a given job.  If this listener is notified of a job completing that has a\n * mapping, then it will then attempt to trigger the follow-up job.  This\n * achieves \"job chaining\", or a \"poor man's workflow\".\n *\n * <p>Generally an instance of this listener would be registered as a global\n * job listener, rather than being registered directly to a given job.</p>\n *\n * <p>If for some reason there is a failure creating the trigger for the\n * follow-up job (which would generally only be caused by a rare serious\n * failure in the system, or the non-existence of the follow-up job), an error\n * message is logged, but no other action is taken. If you need more rigorous\n * handling of the error, consider scheduling the triggering of the flow-up\n * job within your job itself.</p>\n *\n * @author James House (jhouse AT revolition DOT net)\n */\npublic class JobChainingJobListener extends JobListenerSupport {\n\n    private final String name;\n    private final Map<JobKey, JobKey> chainLinks;\n\n\n    /**\n     * Construct an instance with the given name.\n     *\n     * @param name the name of this instance\n     */\n    public JobChainingJobListener(String name) {\n        if(name == null) {\n            throw new IllegalArgumentException(\"Listener name cannot be null!\");\n        }\n        this.name = name;\n        chainLinks = new HashMap<>();\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Add a chain mapping - when the Job identified by the first key completes\n     * the job identified by the second key will be triggered.\n     *\n     * @param firstJob a JobKey with the name and group of the first job\n     * @param secondJob a JobKey with the name and group of the follow-up job\n     */\n    public void addJobChainLink(JobKey firstJob, JobKey secondJob) {\n\n        if(firstJob == null || secondJob == null) {\n            throw new IllegalArgumentException(\"Key cannot be null!\");\n        }\n\n        if(firstJob.getName() == null || secondJob.getName() == null) {\n            throw new IllegalArgumentException(\"Key cannot have a null name!\");\n        }\n\n        chainLinks.put(firstJob, secondJob);\n    }\n\n    @Override\n    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {\n\n        JobKey sj = chainLinks.get(context.getJobDetail().getKey());\n\n        if(sj == null) {\n            return;\n        }\n\n        getLog().info(\"Job '{}' will now chain to Job '{}'\", context.getJobDetail().getKey(), sj);\n\n        try {\n             context.getScheduler().triggerJob(sj);\n        } catch(SchedulerException se) {\n            getLog().error(\"Error encountered during chaining to Job '{}'\", sj, se);\n        }\n    }\n}\n\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/JobListenerSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.listeners;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.JobListener;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * A helpful abstract base class for implementors of \n * <code>{@link org.quartz.JobListener}</code>.\n * \n * <p>\n * The methods in this class are empty so you only need to override the  \n * subset for the <code>{@link org.quartz.JobListener}</code> events\n * you care about.\n * </p>\n * \n * <p>\n * You are required to implement <code>{@link org.quartz.JobListener#getName()}</code> \n * to return the unique name of your <code>JobListener</code>.  \n * </p>\n * \n * @see org.quartz.JobListener\n */\npublic abstract class JobListenerSupport implements JobListener {\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /**\n     * Get the <code>{@link org.slf4j.Logger}</code> for this\n     * class's category.  This should be used by subclasses for logging.\n     */\n    protected Logger getLog() {\n        return log;\n    }\n\n    public void jobToBeExecuted(JobExecutionContext context) {\n    }\n\n    public void jobExecutionVetoed(JobExecutionContext context) {\n    }\n\n    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/SchedulerListenerSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.listeners;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerListener;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A helpful abstract base class for implementors of \n * <code>{@link org.quartz.SchedulerListener}</code>.\n * \n * <p>\n * The methods in this class are empty so you only need to override the  \n * subset for the <code>{@link org.quartz.SchedulerListener}</code> events\n * you care about.\n * </p>\n * \n * @see org.quartz.SchedulerListener\n */\npublic abstract class SchedulerListenerSupport implements SchedulerListener {\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /**\n     * Get the <code>{@link org.slf4j.Logger}</code> for this\n     * class's category.  This should be used by subclasses for logging.\n     */\n    protected Logger getLog() {\n        return log;\n    }\n\n    public void jobAdded(JobDetail jobDetail) {\n    }\n\n    public void jobDeleted(JobKey jobKey) {\n    }\n\n    public void jobPaused(JobKey jobKey) {\n    }\n\n    public void jobResumed(JobKey jobKey) {\n    }\n\n    public void jobScheduled(Trigger trigger) {\n    }\n\n    public void jobsPaused(String jobGroup) {\n    }\n\n    public void jobsResumed(String jobGroup) {\n    }\n\n    public void jobUnscheduled(TriggerKey triggerKey) {\n    }\n\n    public void schedulerError(String msg, SchedulerException cause) {\n    }\n\n    public void schedulerInStandbyMode() {\n    }\n\n    public void schedulerShutdown() {\n    }\n\n    public void schedulerShuttingdown() {\n    }\n\n    public void schedulerStarted() {\n    }\n\n    public void schedulerStarting() {\n    }\n\n    public void triggerFinalized(Trigger trigger) {\n    }\n\n    public void triggerPaused(TriggerKey triggerKey) {\n    }\n\n    public void triggerResumed(TriggerKey triggerKey) {\n    }\n\n    public void triggersPaused(String triggerGroup) {\n    }\n\n    public void triggersResumed(String triggerGroup) {\n    }\n    \n    public void schedulingDataCleared() {\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/listeners/TriggerListenerSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.listeners;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.TriggerListener;\nimport org.quartz.Trigger;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\n\n/**\n * A helpful abstract base class for implementors of \n * <code>{@link org.quartz.TriggerListener}</code>.\n * \n * <p>\n * The methods in this class are empty so you only need to override the  \n * subset for the <code>{@link org.quartz.TriggerListener}</code> events\n * you care about.\n * </p>\n * \n * <p>\n * You are required to implement <code>{@link org.quartz.TriggerListener#getName()}</code> \n * to return the unique name of your <code>TriggerListener</code>.  \n * </p>\n * \n * @see org.quartz.TriggerListener\n */\npublic abstract class TriggerListenerSupport implements TriggerListener {\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /**\n     * Get the <code>{@link org.slf4j.Logger}</code> for this\n     * class's category.  This should be used by subclasses for logging.\n     */\n    protected Logger getLog() {\n        return log;\n    }\n\n    public void triggerFired(Trigger trigger, JobExecutionContext context) {\n    }\n\n    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {\n        return false;\n    }\n\n    public void triggerMisfired(Trigger trigger) {\n    }\n\n    public void triggerComplete(\n        Trigger trigger,\n        JobExecutionContext context,\n        CompletedExecutionInstruction triggerInstructionCode) {\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/management/ManagementRESTServiceConfiguration.java",
    "content": "/**\n *  Copyright Terracotta, Inc.\n *  Copyright IBM Corp. 2024, 2025\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage org.quartz.management;\n\n\n/**\n * Configuration class of management REST services.\n * \n * @author Ludovic Orban\n * \n *         TODO : could be merged with ehcache\n *         ManagementRESTServiceConfiguration in a common module\n */\npublic class ManagementRESTServiceConfiguration {\n\n    /**\n     * Default bind value.\n     */\n    public static final String DEFAULT_BIND = \"0.0.0.0:9888\";\n\n    /**\n     * Default timeout for the connection to the configured security service\n     */\n    public static final int DEFAULT_SECURITY_SVC_TIMEOUT = 5 * 1000;\n\n    private volatile boolean enabled = false;\n    private volatile String securityServiceLocation;\n    private volatile int securityServiceTimeout = DEFAULT_SECURITY_SVC_TIMEOUT;\n    private volatile String bind = DEFAULT_BIND;\n\n    // private volatile int sampleHistorySize =\n    // CacheStatisticsSampler.DEFAULT_HISTORY_SIZE;\n    // private volatile int sampleIntervalSeconds =\n    // CacheStatisticsSampler.DEFAULT_INTERVAL_SECS;\n    // private volatile int sampleSearchIntervalSeconds =\n    // CacheStatisticsSampler.DEFAULT_SEARCH_INTERVAL_SEC;\n\n    /**\n     * Check if the REST services should be enabled or not.\n     * @return true if REST services should be enabled.\n     */\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    /**\n     * Set that the REST services should be enabled or disabled.\n     * @param enabled true if the REST services should be enabled.\n     */\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    /**\n     * Returns the security service location required for trusted identity assertion to the embedded REST management\n     * service.  This feature is only available with an enterprise license.\n     * <p>\n     * If this value is set, then this service will require secure dialog with the TMS or other 3rd party REST client\n     * implementations. The service furnished by the enterprise version of the TMC is located is provided at /api/assertIdentity.\n     * </p>\n     *\n     * @return a string representing the URL of the security service.\n     */\n    public String getSecurityServiceLocation() {\n        return securityServiceLocation;\n    }\n\n    /**\n     * Sets the security service location required for trusted identity assertion to the embedded REST management\n     * service.  This feature is only available with an enterprise license.\n     * <p>\n     * If this value is set, then this service will require secure dialog with the TMS or other 3rd party REST client\n     * implementations. The service furnished by the enterprise version of the TMC is located is provided at /api/assertIdentity.\n     * </p>\n     *\n     * @param securityServiceURL a string representing the URL of the security service.\n     */\n    public void setSecurityServiceLocation(String securityServiceURL) {\n        this.securityServiceLocation = securityServiceURL;\n    }\n\n    /**\n     * Returns the connection/read timeout value for the security service in milliseconds.\n     *\n     * @return security service timeout\n     */\n    public int getSecurityServiceTimeout() {\n        return securityServiceTimeout;\n    }\n\n    /**\n     * Sets the connection/read timeout value for the security service in milliseconds.\n     *\n     * @param securityServiceTimeout milliseconds to timeout\n     */\n    public void setSecurityServiceTimeout(int securityServiceTimeout) {\n        this.securityServiceTimeout = securityServiceTimeout;\n    }\n\n    /**\n     * Get the host:port pair to which the REST server should be bound.\n     * Format is: [IP address|host name]:[port number]\n     * @return the host:port pair to which the REST server should be bound.\n     */\n    public String getBind() {\n        return bind;\n    }\n\n    /**\n     * Get the host part of the host:port pair to which the REST server should be bound.\n     * @return the host part of the host:port pair to which the REST server should be bound.\n     */\n    public String getHost() {\n        if (bind == null) {\n            return null;\n        }\n        return bind.split(\"\\\\:\")[0];\n    }\n\n    /**\n     * Get the port part of the host:port pair to which the REST server should be bound.\n     * @return the port part of the host:port pair to which the REST server should be bound.\n     */\n    public int getPort() {\n        if (bind == null) {\n            return -1;\n        }\n        String[] split = bind.split(\"\\\\:\");\n        if (split.length != 2) {\n            throw new IllegalArgumentException(\"invalid bind format (should be IP:port)\");\n        }\n        return Integer.parseInt(split[1]);\n    }\n\n    /**\n     * Set the host:port pair to which the REST server should be bound.\n     * @param bind host:port pair to which the REST server should be bound.\n     */\n    public void setBind(String bind) {\n        this.bind = bind;\n    }\n\n    /**\n     * Returns the sample history size to be applied to the {@link SampledCounterConfig} for sampled statistics\n     *\n     * @return the sample history size\n     */\n    // public int getSampleHistorySize() {\n    // return sampleHistorySize;\n    // }\n\n    /**\n     * Sets the sample history size to be applied to the {@link SampledCounterConfig} for sampled statistics\n     *\n     * @param sampleHistorySize to set\n     */\n    // public void setSampleHistorySize(final int sampleHistorySize) {\n    // this.sampleHistorySize = sampleHistorySize;\n    // }\n\n    /**\n     * Returns the sample interval in seconds to be applied to the {@link SampledCounterConfig} for sampled statistics\n     *\n     * @return the sample interval in seconds\n     */\n    // public int getSampleIntervalSeconds() {\n    // return sampleIntervalSeconds;\n    // }\n\n    /**\n     * Sets the sample interval in seconds to be applied to the {@link SampledCounterConfig} for sampled statistics\n     *\n     * @param sampleIntervalSeconds to set\n     */\n    // public void setSampleIntervalSeconds(final int sampleIntervalSeconds) {\n    // this.sampleIntervalSeconds = sampleIntervalSeconds;\n    // }\n\n    /**\n     * Returns the sample search interval in seconds to be applied to the {@link SampledRateCounterConfig} for sampled statistics\n     *\n     * @return the sample search interval in seconds\n     */\n    // public int getSampleSearchIntervalSeconds() {\n    // return sampleSearchIntervalSeconds;\n    // }\n\n    /**\n     * Sets the sample search interval in seconds to be applied to the {@link SampledCounterConfig} for sampled statistics\n     *\n     * @param sampleSearchInterval to set\n     */\n    // public void setSampleSearchIntervalSeconds(final int\n    // sampleSearchInterval) {\n    // this.sampleSearchIntervalSeconds = sampleSearchInterval;\n    // }\n\n    /**\n     * A factory method for {@link SampledCounterConfig} based on the global settings defined on this object\n     *\n     * @see #getSampleIntervalSeconds()\n     * @see #getSampleHistorySize()\n     *\n     * @return a {@code SampledCounterConfig}\n     */\n    // public SampledCounterConfig makeSampledCounterConfig() {\n    // return new SampledCounterConfig(getSampleIntervalSeconds(),\n    // getSampleHistorySize(), true, 0L);\n    // }\n\n    /**\n     * A factory method for {@link SampledCounterConfig} based on the global settings defined on this object\n     *\n     * @see #getSampleIntervalSeconds()\n     * @see #getSampleHistorySize()\n     *\n     * @return a {@code SampledCounterConfig}\n     */\n    // public SampledRateCounterConfig makeSampledGetRateCounterConfig() {\n    // return new SampledRateCounterConfig(getSampleIntervalSeconds(),\n    // getSampleHistorySize(), true);\n    // }\n\n    /**\n     * A factory method for {@link SampledCounterConfig} based on the global settings defined on this object\n     *\n     * @see #getSampleSearchIntervalSeconds()\n     * @see #getSampleHistorySize()\n     *\n     * @return a {@code SampledCounterConfig}\n     */\n    // public SampledRateCounterConfig makeSampledSearchRateCounterConfig() {\n    // return new SampledRateCounterConfig(getSampleSearchIntervalSeconds(),\n    // getSampleHistorySize(), true);\n    // }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/management/ManagementServer.java",
    "content": "/**\n *  Copyright Terracotta, Inc.\n *  Copyright IBM Corp. 2024, 2025\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.management;\n\nimport org.quartz.core.QuartzScheduler;\n\n\n\n/**\n * Interface implemented by management servers.\n *\n * @author Ludovic Orban\n * @author brandony\n */\npublic interface ManagementServer {\n\n    /**\n     * Start the management server\n     */\n    void start();\n\n    /**\n     * Stop the management server\n     */\n    void stop();\n\n    /**\n     * Puts the submitted resource under the purview of this {@code ManagementServer}.\n     *\n     * @param managedResource the resource to be managed\n     */\n    void register(QuartzScheduler managedResource);\n\n    /**\n     * Removes the submitted resource under the purview of this {@code ManagementServer}.\n     *\n     * @param managedResource the resource to be managed\n     */\n    void unregister(QuartzScheduler managedResource);\n\n    /**\n     * Returns true if this {@code ManagementServer} has any resources registered.\n     *\n     * @return true if actively managing resources, false if not.\n     */\n    boolean hasRegistered();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz</title>\n</head>\n<body>\n<p>The main package of <b>Quartz</b>, containing the client-side interfaces.</p>\n\n<br>\n<br>\n<hr>\n<p>See the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project for more information.</p>\n\n   \n<p>Quartz provides a builder-style API for constructing scheduling-related\nentities via a Domain-Specific Language (DSL).  The DSL can best be\nutilized through the usage of static imports of the methods on the classes\n<code>TriggerBuilder</code>, <code>JobBuilder</code>, \n<code>DateBuilder</code>, <code>JobKey</code>, <code>TriggerKey</code> \nand the various <code>ScheduleBuilder</code> implementations.</p>\n\n<p>Client code can then use the DSL to write code such as this:</p>\n<pre>\n        JobDetail job = newJob(MyJob.class)\n            .withIdentity(\"myJob\")\n            .build();\n            \n        Trigger trigger = newTrigger() \n            .withIdentity(triggerKey(\"myTrigger\", \"myTriggerGroup\"))\n            .withSchedule(simpleSchedule()\n                .withIntervalInHours(1)\n                .repeatForever())\n            .startAt(futureDate(10, MINUTES))\n            .build();\n        \n        scheduler.scheduleJob(job, trigger);\n</pre>\n\n</body>\n</html>"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/SchedulerPluginWithUserTransactionSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.plugins;\n\nimport jakarta.transaction.Status;\nimport jakarta.transaction.UserTransaction;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.ee.jta.UserTransactionHelper;\nimport org.quartz.spi.SchedulerPlugin;\n\n/**\n * Base class for plugins that wish to support having their start and\n * shutdown methods run within a <code>UserTransaction</code>.  This is \n * often necessary if using the JobStoreCMT and the plugin interacts with\n * jobs/triggers. \n * \n * <p>\n * The subclass should implement start(UserTransaction) and \n * shutdown(UserTransaction).  The <code>UserTransaction</code> will be \n * non-null if property <em>wrapInUserTransaction</em> is set to true.\n * </p>\n * <p>\n * For convenience, this base class also provides an initialize() implementation\n * which saves the scheduler and plugin name, as well as getLog() for logging.\n * </p>\n */\npublic abstract class SchedulerPluginWithUserTransactionSupport implements\n    SchedulerPlugin {\n\n    private String name;\n    private Scheduler scheduler;\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    // Properties\n    \n    private boolean wrapInUserTransaction = false;\n\n    /**\n     * <p>\n     * Called when the associated <code>Scheduler</code> is started, in order\n     * to let the plug-in know it can now make calls into the scheduler if it\n     * needs to.\n     * </p>\n     * \n     * <p>\n     * If UserTransaction is not null, the plugin can call setRollbackOnly()\n     * on it to signal that the wrapped transaction should rollback.  \n     * </p>\n     * \n     * @param userTransaction The UserTransaction object used to provide a \n     * transaction around the start() operation.  It will be null if \n     * <em>wrapInUserTransaction</em> is false or if the transaction failed\n     * to be started.\n     */\n    protected void start(UserTransaction userTransaction) {\n    }\n\n    /**\n     * <p>\n     * Called in order to inform the <code>SchedulerPlugin</code> that it\n     * should free up all of it's resources because the scheduler is shutting\n     * down.\n     * </p>\n     * \n     * <p>\n     * If UserTransaction is not null, the plugin can call setRollbackOnly()\n     * on it to signal that the wrapped transaction should rollback.  \n     * </p>\n     * \n     * @param userTransaction The UserTransaction object used to provide a \n     * transaction around the shutdown() operation.  It will be null if \n     * <em>wrapInUserTransaction</em> is false or if the transaction failed\n     * to be started.\n     */\n    protected void shutdown(UserTransaction userTransaction) {\n    }\n\n    /**\n     * Get the commons Logger for this class.\n     */\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * Get the name of this plugin.  Set as part of initialize().\n     */\n    protected String getName() {\n        return name;\n    }\n\n    /**\n     * Get this plugin's <code>Scheduler</code>.  Set as part of initialize().\n     */\n    protected Scheduler getScheduler() {\n        return scheduler;\n    }\n\n    public void initialize(String pname, Scheduler sched) throws SchedulerException {\n        this.name = pname;\n        this.scheduler = sched;\n    }\n    \n    /**\n     * Wrap the start() and shutdown() methods in a UserTransaction.  This is necessary\n     * for some plugins if using the JobStoreCMT.\n     */\n    public boolean getWrapInUserTransaction() {\n        return wrapInUserTransaction;\n    }\n\n    /**\n     * Wrap the start() and shutdown() methods in a UserTransaction.  This is necessary\n     * for some plugins if using the JobStoreCMT.\n     */\n    public void setWrapInUserTransaction(boolean wrapInUserTransaction) {\n        this.wrapInUserTransaction = wrapInUserTransaction;\n    }\n\n    /**\n     * Based on the value of <em>wrapInUserTransaction</em>, wraps the\n     * call to start(UserTransaction) in a UserTransaction.\n     */\n    public void start() {\n        UserTransaction userTransaction = startUserTransaction();\n        try {\n            start(userTransaction);\n        } finally {\n            resolveUserTransaction(userTransaction);\n        }\n    }\n\n    /**\n     * Based on the value of <em>wrapInUserTransaction</em>, wraps the\n     * call to shutdown(UserTransaction) in a UserTransaction.\n     */\n    public void shutdown() {\n        UserTransaction userTransaction = startUserTransaction();\n        try {\n            shutdown(userTransaction);\n        } finally {\n            resolveUserTransaction(userTransaction);\n        }\n    }\n        \n    /**\n     * If <em>wrapInUserTransaction</em> is true, starts a new UserTransaction \n     * and returns it. Otherwise, or if establishing the transaction fail, it \n     * will return null.\n     */\n    private UserTransaction startUserTransaction() {\n        if (!wrapInUserTransaction) {\n            return null;\n        }\n        \n        UserTransaction userTransaction = null;\n        try {\n            userTransaction = UserTransactionHelper.lookupUserTransaction();\n            userTransaction.begin();\n        } catch (Throwable t) {\n            UserTransactionHelper.returnUserTransaction(userTransaction);\n            userTransaction = null;\n            getLog().error(\"Failed to start UserTransaction for plugin: {}\", getName(), t);\n        }\n        \n        return userTransaction;\n    }\n    \n    /**\n     * If the given UserTransaction is not null, it is committed/rolled back,\n     * and then returned to the UserTransactionHelper.\n     */\n    private void resolveUserTransaction(UserTransaction userTransaction) {\n        if (userTransaction != null) {\n            try {\n                if (userTransaction.getStatus() == Status.STATUS_MARKED_ROLLBACK) {\n                    userTransaction.rollback();\n                } else {\n                    userTransaction.commit();\n                } \n            } catch (Throwable t) {\n                getLog().error(\"Failed to resolve UserTransaction for plugin: {}\", getName(), t);\n            } finally {\n                UserTransactionHelper.returnUserTransaction(userTransaction);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/history/LoggingJobHistoryPlugin.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.history;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.JobListener;\nimport org.quartz.impl.matchers.EverythingMatcher;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\n\nimport java.text.MessageFormat;\n\n/**\n * Logs a history of all job executions (and execution vetoes) via the slf4j.\n * \n * <p>\n * The logged message is customizable by setting one of the following message\n * properties to a String that conforms to the syntax of <code>java.util.MessageFormat</code>.\n * </p>\n * \n * <p>\n * JobToBeFiredMessage - available message data are:</p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Job's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Job's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The current time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>String</td>\n * <td>The Trigger's name.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>String</td>\n * <td>The Triggers's group.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Job {1}.{0} fired (by trigger {4}.{3}) at:\n * {2, date, HH:mm:ss MM/dd/yyyy}\"</i>\n * </p>\n * \n * \n * <p>\n * JobSuccessMessage - available message data are: </p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Job's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Job's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The current time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>String</td>\n * <td>The Trigger's name.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>String</td>\n * <td>The Triggers's group.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * <tr>\n * <td>8</td>\n * <td>Object</td>\n * <td>The string value (toString() having been called) of the result (if any) \n *      that the Job set on the JobExecutionContext, with on it.  \"NULL\" if no \n *      result was set.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Job {1}.{0} execution complete at {2, date,\n * HH:mm:ss MM/dd/yyyy} and reports: {8}\"</i>\n * </p>\n * \n * <p>\n * JobFailedMessage - available message data are: </p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Job's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Job's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The current time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>String</td>\n * <td>The Trigger's name.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>String</td>\n * <td>The Triggers's group.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * <tr>\n * <td>8</td>\n * <td>String</td>\n * <td>The message from the thrown JobExecution Exception.\n * </td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Job {1}.{0} execution failed at {2, date,\n * HH:mm:ss MM/dd/yyyy} and reports: {8}\"</i>\n * </p>\n * \n * \n * <p>\n * JobWasVetoedMessage - available message data are:</p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Job's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Job's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The current time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>String</td>\n * <td>The Trigger's name.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>String</td>\n * <td>The Triggers's group.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Job {1}.{0} was vetoed.  It was to be fired \n * (by trigger {4}.{3}) at: {2, date, HH:mm:ss MM/dd/yyyy}\"</i>\n * </p>\n * \n * \n * @author James House\n */\npublic class LoggingJobHistoryPlugin implements SchedulerPlugin, JobListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private String name;\n\n    private String jobToBeFiredMessage = \"Job {1}.{0} fired (by trigger {4}.{3}) at: {2, date, HH:mm:ss MM/dd/yyyy}\";\n    \n    private String jobSuccessMessage = \"Job {1}.{0} execution complete at {2, date, HH:mm:ss MM/dd/yyyy} and reports: {8}\";\n\n    private String jobFailedMessage = \"Job {1}.{0} execution failed at {2, date, HH:mm:ss MM/dd/yyyy} and reports: {8}\";\n\n    private String jobWasVetoedMessage = \"Job {1}.{0} was vetoed.  It was to be fired (by trigger {4}.{3}) at: {2, date, HH:mm:ss MM/dd/yyyy}\";\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public LoggingJobHistoryPlugin() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * Get the message that is logged when a Job successfully completes its \n     * execution.\n     */\n    public String getJobSuccessMessage() {\n        return jobSuccessMessage;\n    }\n\n    /**\n     * Get the message that is logged when a Job fails its \n     * execution.\n     */\n    public String getJobFailedMessage() {\n        return jobFailedMessage;\n    }\n\n    /**\n     * Get the message that is logged when a Job is about to execute.\n     */\n    public String getJobToBeFiredMessage() {\n        return jobToBeFiredMessage;\n    }\n\n    /**\n     * Set the message that is logged when a Job successfully completes its \n     * execution.\n     * \n     * @param jobSuccessMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setJobSuccessMessage(String jobSuccessMessage) {\n        this.jobSuccessMessage = jobSuccessMessage;\n    }\n\n    /**\n     * Set the message that is logged when a Job fails its \n     * execution.\n     * \n     * @param jobFailedMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setJobFailedMessage(String jobFailedMessage) {\n        this.jobFailedMessage = jobFailedMessage;\n    }\n\n    /**\n     * Set the message that is logged when a Job is about to execute.\n     * \n     * @param jobToBeFiredMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setJobToBeFiredMessage(String jobToBeFiredMessage) {\n        this.jobToBeFiredMessage = jobToBeFiredMessage;\n    }\n\n    /**\n     * Get the message that is logged when a Job execution is vetoed by a\n     * trigger listener.\n     */\n    public String getJobWasVetoedMessage() {\n        return jobWasVetoedMessage;\n    }\n\n    /**\n     * Set the message that is logged when a Job execution is vetoed by a\n     * trigger listener.\n     * \n     * @param jobWasVetoedMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setJobWasVetoedMessage(String jobWasVetoedMessage) {\n        this.jobWasVetoedMessage = jobWasVetoedMessage;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * SchedulerPlugin Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called during creation of the <code>Scheduler</code> in order to give\n     * the <code>SchedulerPlugin</code> a chance to initialize.\n     *\n     * @throws SchedulerConfigException\n     *           if there is an error initializing.\n     */\n    public void initialize(String pname, Scheduler scheduler,ClassLoadHelper classLoadHelper)\n        throws SchedulerException {\n        this.name = pname;\n        scheduler.getListenerManager().addJobListener(this, EverythingMatcher.allJobs());\n    }\n\n    public void start() {\n        // do nothing...\n    }\n\n    /**\n     * Called in order to inform the <code>SchedulerPlugin</code> that it\n     * should free up all of it's resources because the scheduler is shutting\n     * down.\n     */\n    public void shutdown() {\n        // nothing to do...\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * JobListener Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /*\n     * Object[] arguments = { new Integer(7), new\n     * Date(System.currentTimeMillis()), \"a disturbance in the Force\" };\n     * \n     * String result = MessageFormat.format( \"At {1,time} on {1,date}, there\n     * was {2} on planet {0,number,integer}.\", arguments);\n     */\n\n    public String getName() {\n        return name;\n    }\n\n    /** \n     * @see org.quartz.JobListener#jobToBeExecuted(JobExecutionContext)\n     */\n    public void jobToBeExecuted(JobExecutionContext context) {\n        if (!getLog().isInfoEnabled()) {\n            return;\n        } \n        \n        Trigger trigger = context.getTrigger();\n\n        Object[] args = {\n            context.getJobDetail().getKey().getName(),\n            context.getJobDetail().getKey().getGroup(), new java.util.Date(),\n            trigger.getKey().getName(), trigger.getKey().getGroup(),\n            trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n                context.getRefireCount()\n        };\n\n        getLog().info(MessageFormat.format(getJobToBeFiredMessage(), args));\n    }\n    \n    /** \n     * @see org.quartz.JobListener#jobWasExecuted(JobExecutionContext, JobExecutionException)\n     */\n    public void jobWasExecuted(JobExecutionContext context,\n            JobExecutionException jobException) {\n\n        Trigger trigger = context.getTrigger();\n        \n        Object[] args;\n        \n        if (jobException != null) {\n            if (!getLog().isWarnEnabled()) {\n                return;\n            } \n            \n            String errMsg = jobException.getMessage();\n            args = \n                new Object[] {\n                    context.getJobDetail().getKey().getName(),\n                    context.getJobDetail().getKey().getGroup(), new java.util.Date(),\n                    trigger.getKey().getName(), trigger.getKey().getGroup(),\n                    trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n                        context.getRefireCount(), errMsg\n                };\n            \n            getLog().warn(MessageFormat.format(getJobFailedMessage(), args), jobException); \n        } else {\n            if (!getLog().isInfoEnabled()) {\n                return;\n            } \n            \n            String result = String.valueOf(context.getResult());\n            args =\n                new Object[] {\n                    context.getJobDetail().getKey().getName(),\n                    context.getJobDetail().getKey().getGroup(), new java.util.Date(),\n                    trigger.getKey().getName(), trigger.getKey().getGroup(),\n                    trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n                        context.getRefireCount(), result\n                };\n            \n            getLog().info(MessageFormat.format(getJobSuccessMessage(), args));\n        }\n    }\n\n    /** \n     * @see org.quartz.JobListener#jobExecutionVetoed(org.quartz.JobExecutionContext)\n     */\n    public void jobExecutionVetoed(JobExecutionContext context) {\n        \n        if (!getLog().isInfoEnabled()) {\n            return;\n        } \n        \n        Trigger trigger = context.getTrigger();\n\n        Object[] args = {\n            context.getJobDetail().getKey().getName(),\n            context.getJobDetail().getKey().getGroup(), new java.util.Date(),\n            trigger.getKey().getName(), trigger.getKey().getGroup(),\n            trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n                context.getRefireCount()\n        };\n\n        getLog().info(MessageFormat.format(getJobWasVetoedMessage(), args));\n    }\n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.history;\n\nimport java.text.MessageFormat;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerListener;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.impl.matchers.EverythingMatcher;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\n\n/**\n * Logs a history of all trigger firings via slf4j.\n * \n * <p>\n * The logged message is customizable by setting one of the following message\n * properties to a String that conforms to the syntax of <code>java.util.MessageFormat</code>.\n * </p>\n * \n * <p>\n * TriggerFiredMessage - available message data are: </p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Trigger's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Trigger's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>Date</td>\n * <td>The actual fire time.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>String</td>\n * <td>The Job's name.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>String</td>\n * <td>The Job's group.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Trigger {1}.{0} fired job {6}.{5} at: {4,\n * date, HH:mm:ss MM/dd/yyyy}\"</i>\n * </p>\n * \n * <p>\n * TriggerMisfiredMessage - available message data are: </p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Trigger's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Trigger's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>Date</td>\n * <td>The actual fire time. (the time the misfire was detected/handled)</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>String</td>\n * <td>The Job's name.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>String</td>\n * <td>The Job's group.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Trigger {1}.{0} misfired job {6}.{5} at:\n * {4, date, HH:mm:ss MM/dd/yyyy}. Should have fired at: {3, date, HH:mm:ss\n * MM/dd/yyyy}\"</i>\n * </p>\n * \n * <p>\n * TriggerCompleteMessage - available message data are: </p> <table>\n * <caption>List of available data for messages.</caption>\n * <tr>\n * <th>Element</th>\n * <th>Data Type</th>\n * <th>Description</th>\n * </tr>\n * <tr>\n * <td>0</td>\n * <td>String</td>\n * <td>The Trigger's Name.</td>\n * </tr>\n * <tr>\n * <td>1</td>\n * <td>String</td>\n * <td>The Trigger's Group.</td>\n * </tr>\n * <tr>\n * <td>2</td>\n * <td>Date</td>\n * <td>The scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>3</td>\n * <td>Date</td>\n * <td>The next scheduled fire time.</td>\n * </tr>\n * <tr>\n * <td>4</td>\n * <td>Date</td>\n * <td>The job completion time.</td>\n * </tr>\n * <tr>\n * <td>5</td>\n * <td>String</td>\n * <td>The Job's name.</td>\n * </tr>\n * <tr>\n * <td>6</td>\n * <td>String</td>\n * <td>The Job's group.</td>\n * </tr>\n * <tr>\n * <td>7</td>\n * <td>Integer</td>\n * <td>The re-fire count from the JobExecutionContext.</td>\n * </tr>\n * <tr>\n * <td>8</td>\n * <td>Integer</td>\n * <td>The trigger's resulting instruction code.</td>\n * </tr>\n * <tr>\n * <td>9</td>\n * <td>String</td>\n * <td>A human-readable translation of the trigger's resulting instruction\n * code.</td>\n * </tr>\n * </table>\n * <p>\n * The default message text is <i>\"Trigger {1}.{0} completed firing job\n * {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction\n * code: {9}\"</i>\n * </p>\n * \n * @author James House\n */\npublic class LoggingTriggerHistoryPlugin implements SchedulerPlugin,\n        TriggerListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private String name;\n\n    private String triggerFiredMessage = \"Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}\";\n\n    private String triggerMisfiredMessage = \"Trigger {1}.{0} misfired job {6}.{5}  at: {4, date, HH:mm:ss MM/dd/yyyy}.  Should have fired at: {3, date, HH:mm:ss MM/dd/yyyy}\";\n\n    private String triggerCompleteMessage = \"Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}\";\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public LoggingTriggerHistoryPlugin() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * Get the message that is printed upon the completion of a trigger's\n     * firing.\n     * \n     * @return String\n     */\n    public String getTriggerCompleteMessage() {\n        return triggerCompleteMessage;\n    }\n\n    /**\n     * Get the message that is printed upon a trigger's firing.\n     * \n     * @return String\n     */\n    public String getTriggerFiredMessage() {\n        return triggerFiredMessage;\n    }\n\n    /**\n     * Get the message that is printed upon a trigger's mis-firing.\n     * \n     * @return String\n     */\n    public String getTriggerMisfiredMessage() {\n        return triggerMisfiredMessage;\n    }\n\n    /**\n     * Set the message that is printed upon the completion of a trigger's\n     * firing.\n     * \n     * @param triggerCompleteMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setTriggerCompleteMessage(String triggerCompleteMessage) {\n        this.triggerCompleteMessage = triggerCompleteMessage;\n    }\n\n    /**\n     * Set the message that is printed upon a trigger's firing.\n     * \n     * @param triggerFiredMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setTriggerFiredMessage(String triggerFiredMessage) {\n        this.triggerFiredMessage = triggerFiredMessage;\n    }\n\n    /**\n     * Set the message that is printed upon a trigger's firing.\n     * \n     * @param triggerMisfiredMessage\n     *          String in java.text.MessageFormat syntax.\n     */\n    public void setTriggerMisfiredMessage(String triggerMisfiredMessage) {\n        this.triggerMisfiredMessage = triggerMisfiredMessage;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * SchedulerPlugin Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called during creation of the <code>Scheduler</code> in order to give\n     * the <code>SchedulerPlugin</code> a chance to initialize.\n     *\n     * @throws SchedulerConfigException\n     *           if there is an error initializing.\n     */\n    public void initialize(String pname, Scheduler scheduler, ClassLoadHelper classLoadHelper)\n        throws SchedulerException {\n        this.name = pname;\n\n        scheduler.getListenerManager().addTriggerListener(this,  EverythingMatcher.allTriggers());\n    }\n\n    public void start() {\n        // do nothing...\n    }\n\n    /**\n     * Called in order to inform the <code>SchedulerPlugin</code> that it\n     * should free up all of it's resources because the scheduler is shutting\n     * down.\n     */\n    public void shutdown() {\n        // nothing to do...\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * TriggerListener Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /*\n     * Object[] arguments = { new Integer(7), new\n     * Date(System.currentTimeMillis()), \"a disturbance in the Force\" };\n     * \n     * String result = MessageFormat.format( \"At {1,time} on {1,date}, there\n     * was {2} on planet {0,number,integer}.\", arguments);\n     */\n\n    public String getName() {\n        return name;\n    }\n\n    public void triggerFired(Trigger trigger, JobExecutionContext context) {\n        if (!getLog().isInfoEnabled()) {\n            return;\n        } \n        \n        Object[] args = {\n            trigger.getKey().getName(), trigger.getKey().getGroup(),\n            trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n            new java.util.Date(), context.getJobDetail().getKey().getName(),\n            context.getJobDetail().getKey().getGroup(),\n                context.getRefireCount()\n        };\n\n        getLog().info(MessageFormat.format(getTriggerFiredMessage(), args));\n    }\n\n    public void triggerMisfired(Trigger trigger) {\n        if (!getLog().isInfoEnabled()) {\n            return;\n        } \n        \n        Object[] args = {\n            trigger.getKey().getName(), trigger.getKey().getGroup(),\n            trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n            new java.util.Date(), trigger.getJobKey().getName(),\n            trigger.getJobKey().getGroup()\n        };\n\n        getLog().info(MessageFormat.format(getTriggerMisfiredMessage(), args));\n    }\n\n    public void triggerComplete(Trigger trigger, JobExecutionContext context,\n            CompletedExecutionInstruction triggerInstructionCode) {\n        if (!getLog().isInfoEnabled()) {\n            return;\n        } \n        \n        String instrCode = \"UNKNOWN\";\n        if (triggerInstructionCode == CompletedExecutionInstruction.DELETE_TRIGGER) {\n            instrCode = \"DELETE TRIGGER\";\n        } else if (triggerInstructionCode == CompletedExecutionInstruction.NOOP) {\n            instrCode = \"DO NOTHING\";\n        } else if (triggerInstructionCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) {\n            instrCode = \"RE-EXECUTE JOB\";\n        } else if (triggerInstructionCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) {\n            instrCode = \"SET ALL OF JOB'S TRIGGERS COMPLETE\";\n        } else if (triggerInstructionCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) {\n            instrCode = \"SET THIS TRIGGER COMPLETE\";\n        }\n\n        Object[] args = {\n            trigger.getKey().getName(), trigger.getKey().getGroup(),\n            trigger.getPreviousFireTime(), trigger.getNextFireTime(),\n            new java.util.Date(), context.getJobDetail().getKey().getName(),\n            context.getJobDetail().getKey().getGroup(),\n                context.getRefireCount(),\n            triggerInstructionCode.toString(), instrCode\n        };\n\n        getLog().info(MessageFormat.format(getTriggerCompleteMessage(), args));\n    }\n\n    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/interrupt/JobInterruptMonitorPlugin.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.plugins.interrupt;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.listeners.TriggerListenerSupport;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This plugin catches the event of job running for a long time (more than the\n * configured max time) and tells the scheduler to \"try\" interrupting it if\n * enabled.\n * \n * @see org.quartz.Scheduler#interrupt(JobKey)\n * \n * @author Rama Chavali\n */\n\npublic class JobInterruptMonitorPlugin extends TriggerListenerSupport implements SchedulerPlugin {\n\n    private static final String JOB_INTERRUPT_MONITOR_KEY = \"JOB_INTERRUPT_MONITOR_KEY\";\n\n    private long DEFAULT_MAX_RUNTIME = 300000;\n    \n    private String name;\n\n    private ScheduledExecutorService executor;\n\n    @SuppressWarnings(\"rawtypes\")\n    private ScheduledFuture future;\n\n    private Scheduler scheduler;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    //Constants\n\n    public static final String AUTO_INTERRUPTIBLE = \"AutoInterruptable\";\n\n    public static final String MAX_RUN_TIME = \"MaxRunTime\";\n\n    public JobInterruptMonitorPlugin() {\n    }\n\n    @Override\n    public void start() {\n    }\n\n    @Override\n\n    public void shutdown() {\n        this.executor.shutdown();\n    }\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    public ScheduledFuture scheduleJobInterruptMonitor(JobKey jobkey, long delay) {\n        return this.executor.schedule(new InterruptMonitor(jobkey, scheduler), delay, TimeUnit.MILLISECONDS);\n    }\n\n    // Bean Property Methods\n\n    public long getDefaultMaxRunTime() {\n        return this.DEFAULT_MAX_RUNTIME;\n    }\n\n    public void setDefaultMaxRunTime(long defaultMaxRunTime) {\n        this.DEFAULT_MAX_RUNTIME = defaultMaxRunTime;\n    }\n\n    // Trigger Listener Methods\n    public String getName() {\n        return name;\n    }\n\n    public void triggerFired(Trigger trigger, JobExecutionContext context) {\n        // Call the scheduleJobInterruptMonitor and capture the ScheduledFuture in context\n        try {\n            // Schedule Monitor only if the job wants AutoInterruptable functionality\n            if (context.getJobDetail().getJobDataMap().getBoolean(AUTO_INTERRUPTIBLE)) {\n                JobInterruptMonitorPlugin monitorPlugin = (JobInterruptMonitorPlugin) context.getScheduler()\n                        .getContext().get(JOB_INTERRUPT_MONITOR_KEY);\n                // Get the MaxRuntime from Job Data if NOT available use DEFAULT_MAX_RUNTIME from Plugin Configuration\n                long jobDataDelay  = DEFAULT_MAX_RUNTIME;\n\n                if (context.getJobDetail().getJobDataMap().get(MAX_RUN_TIME) != null){\n                     jobDataDelay = context.getJobDetail().getJobDataMap().getLong(MAX_RUN_TIME);\n                }\n                future = monitorPlugin.scheduleJobInterruptMonitor(context.getJobDetail().getKey(), jobDataDelay);\n                getLog().debug(\"Job's Interrupt Monitor has been scheduled to interrupt with the delay :{}\", DEFAULT_MAX_RUNTIME);\n            }\n        } catch (SchedulerException e) {\n            getLog().info(\"Error scheduling interrupt monitor {}\", e.getMessage(), e);\n        }\n    }\n\n    public void triggerComplete(Trigger trigger, JobExecutionContext context,\n            CompletedExecutionInstruction triggerInstructionCode) {\n        // cancel the Future if job is complete\n        if (future != null) {\n            future.cancel(true);\n        }\n    }\n\n    @Override\n    public void initialize(String name, Scheduler scheduler, ClassLoadHelper helper) throws SchedulerException {\n\n        getLog().info(\"Registering Job Interrupt Monitor Plugin\");\n        this.name = name;\n        this.executor = Executors.newScheduledThreadPool(1);\n        scheduler.getContext().put(JOB_INTERRUPT_MONITOR_KEY, this);\n        this.scheduler = scheduler;\n        // Set the trigger Listener as this class to the ListenerManager here\n        this.scheduler.getListenerManager().addTriggerListener(this);\n\n    }\n\n    static class InterruptMonitor implements Runnable {\n\n        private final JobKey jobKey;\n        private final Scheduler scheduler;\n\n        private final Logger log = LoggerFactory.getLogger(getClass());\n\n        InterruptMonitor(JobKey jobKey, Scheduler scheduler) {\n            this.jobKey = jobKey;\n            this.scheduler = scheduler;\n        }\n\n        protected Logger getLog() {\n            return log;\n        }\n\n        @Override\n        public void run() {\n            try {\n\n                // Interrupt the job here - using Scheduler API that gets propagated to Job's interrupt\n                getLog().info(\"Interrupting Job as it ran more than the configured max time. Job Details [{}:{}]\", jobKey.getName(), jobKey.getGroup());\n                scheduler.interrupt(jobKey);\n            } catch (SchedulerException x) {\n                getLog().info(\"Error interrupting Job: {}\", x.getMessage(), x);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/management/ShutdownHookPlugin.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.management;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\n\n/**\n * This plugin catches the event of the JVM terminating (such as upon a CTRL-C)\n * and tells the scheduler to shutdown.\n * \n * @see org.quartz.Scheduler#shutdown(boolean)\n * \n * @author James House\n */\npublic class ShutdownHookPlugin implements SchedulerPlugin {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private boolean cleanShutdown = true;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public ShutdownHookPlugin() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Determine whether or not the plug-in is configured to cause a clean\n     * shutdown of the scheduler.\n     * \n     * <p>\n     * The default value is <code>true</code>.\n     * </p>\n     * \n     * @see org.quartz.Scheduler#shutdown(boolean)\n     */\n    public boolean isCleanShutdown() {\n        return cleanShutdown;\n    }\n\n    /**\n     * Set whether or not the plug-in is configured to cause a clean shutdown\n     * of the scheduler.\n     * \n     * <p>\n     * The default value is <code>true</code>.\n     * </p>\n     * \n     * @see org.quartz.Scheduler#shutdown(boolean)\n     */\n    public void setCleanShutdown(boolean b) {\n        cleanShutdown = b;\n    }\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * SchedulerPlugin Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called during creation of the <code>Scheduler</code> in order to give\n     * the <code>SchedulerPlugin</code> a chance to initialize.\n     * </p>\n     * \n     * @throws SchedulerConfigException\n     *           if there is an error initializing.\n     */\n    public void initialize(String name, final Scheduler scheduler, ClassLoadHelper classLoadHelper)\n        throws SchedulerException {\n\n        getLog().info(\"Registering Quartz shutdown hook.\");\n\n        Thread t = new Thread(\"Quartz Shutdown-Hook \"\n                + scheduler.getSchedulerName()) {\n            @Override\n            public void run() {\n                getLog().info(\"Shutting down Quartz...\");\n                try {\n                    scheduler.shutdown(isCleanShutdown());\n                } catch (SchedulerException e) {\n                    getLog().info(\"Error shutting down Quartz: {}\", e.getMessage(), e);\n                }\n            }\n        };\n\n        Runtime.getRuntime().addShutdownHook(t);\n    }\n\n    public void start() {\n        // do nothing.\n    }\n\n    /**\n     * <p>\n     * Called in order to inform the <code>SchedulerPlugin</code> that it\n     * should free up all of it's resources because the scheduler is shutting\n     * down.\n     * </p>\n     */\n    public void shutdown() {\n        // nothing to do in this case (since the scheduler is already shutting\n        // down)\n    }\n\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/xml/FileScanJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.xml;\n\nimport org.quartz.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.net.URLDecoder;\n\n/**\n * Inspects a file and compares whether it's \"last modified date\" has changed\n * since the last time it was inspected.  If the file has been updated, the\n * job invokes a \"call-back\" method on an identified \n * <code>FileScanListener</code> that can be found in the \n * <code>SchedulerContext</code>.\n * \n * @author jhouse\n * @author pl47ypus\n * @see org.quartz.jobs.FileScanListener\n */\n@DisallowConcurrentExecution\n@PersistJobDataAfterExecution\npublic class FileScanJob implements Job {\n\n    /**\n     * <code>JobDataMap</code> key with which to specify \n     * the name of the file to monitor.\n     */\n    public static final String FILE_NAME = \"FILE_NAME\";\n    \n    /**\n     * <code>JobDataMap</code> key with which to specify the \n     * {@link org.quartz.jobs.FileScanListener} to be\n     * notified when the file contents change.  \n     */\n    public static final String FILE_SCAN_LISTENER_NAME = \"FILE_SCAN_LISTENER_NAME\";\n    \n    /**\n     * <code>JobDataMap</code> key with which to specify a <code>long</code>\n     * value that represents the minimum number of milliseconds that must have\n     * past since the file's last modified time in order to consider the file\n     * new/altered.  This is necessary because another process may still be\n     * in the middle of writing to the file when the scan occurs, and the\n     * file may therefore not yet be ready for processing.\n     * \n     * <p>If this parameter is not specified, a default value of \n     * <code>5000</code> (five seconds) will be used.</p>\n     */\n    public static final String MINIMUM_UPDATE_AGE = \"MINIMUM_UPDATE_AGE\";\n\n    private static final String LAST_MODIFIED_TIME = \"LAST_MODIFIED_TIME\";\n    \n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    public FileScanJob() {\n    }\n\n    /** \n     * @see Job#execute(JobExecutionContext)\n     */\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();\n        SchedulerContext schedCtx;\n        try {\n            schedCtx = context.getScheduler().getContext();\n        } catch (SchedulerException e) {\n            throw new JobExecutionException(\"Error obtaining scheduler context.\", e, false);\n        }\n        \n        String fileName = mergedJobDataMap.getString(FILE_NAME);\n        String listenerName = mergedJobDataMap.getString(FILE_SCAN_LISTENER_NAME);\n        \n        if(fileName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    FILE_NAME + \"' not found in merged JobDataMap\");\n        }\n        if(listenerName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    FILE_SCAN_LISTENER_NAME + \"' not found in merged JobDataMap\");\n        }\n\n        FileScanListener listener = (FileScanListener)schedCtx.get(listenerName);\n        \n        if(listener == null) {\n            throw new JobExecutionException(\"FileScanListener named '\" + \n                    listenerName + \"' not found in SchedulerContext\");\n        }\n        \n        long lastDate = -1;\n        if(mergedJobDataMap.containsKey(LAST_MODIFIED_TIME)) {\n            lastDate = mergedJobDataMap.getLong(LAST_MODIFIED_TIME);\n        }\n\n        long minAge = 5000;\n        if(mergedJobDataMap.containsKey(MINIMUM_UPDATE_AGE)) {\n            minAge = mergedJobDataMap.getLong(MINIMUM_UPDATE_AGE);\n        }\n        long maxAgeDate = System.currentTimeMillis() + minAge;\n        \n        \n        long newDate = getLastModifiedDate(fileName);\n        \n        if(newDate < 0) {\n            log.warn(\"File '{}' does not exist.\", fileName);\n            return;\n        }\n        \n        if(lastDate > 0 && (newDate > lastDate && newDate < maxAgeDate)) {\n            // notify call back...\n            log.info(\"File '{}' updated, notifying listener.\", fileName);\n            listener.fileUpdated(fileName); \n        } else if (log.isDebugEnabled()) {\n            log.debug(\"File '{}' unchanged.\", fileName);\n        }\n        \n        // It is the JobDataMap on the JobDetail which is actually stateful\n        context.getJobDetail().getJobDataMap().put(LAST_MODIFIED_TIME, newDate);\n    }\n    \n    protected long getLastModifiedDate(String fileName) {\n        URL resource = Thread.currentThread().getContextClassLoader().getResource(fileName);\n        \n        // Get the absolute path.\n        String filePath = (resource == null) ? fileName : URLDecoder.decode(resource.getFile());\n\n        // If the jobs file is inside a jar point to the jar file (to get it modification date).\n        // Otherwise continue as usual.\n        int jarIndicator = filePath.indexOf('!');\n        \n        if (jarIndicator > 0) {\n            filePath = filePath.substring(5, filePath.indexOf('!'));\n        }\n\n        File file = new File(filePath);\n        \n        if(!file.exists()) {\n            return -1;\n        } else {\n            return file.lastModified();\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/xml/FileScanListener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.xml;\n\n/**\n * Interface for objects wishing to receive a 'call-back' from a \n * <code>FileScanJob</code>.\n * \n * @author jhouse\n * @see FileScanJob\n */\npublic interface FileScanListener {\n\n    void fileUpdated(String fileName);\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/plugins/xml/XMLSchedulingDataProcessorPlugin.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.plugins.xml;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.StringTokenizer;\n\nimport jakarta.transaction.UserTransaction;\n\nimport org.quartz.plugins.xml.FileScanJob;\nimport org.quartz.plugins.xml.FileScanListener;\nimport org.quartz.plugins.SchedulerPluginWithUserTransactionSupport;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.xml.XMLSchedulingDataProcessor;\n\nimport org.quartz.*;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\n/**\n * This plugin loads XML file(s) to add jobs and schedule them with triggers\n * as the scheduler is initialized, and can optionally periodically scan the\n * file for changes.\n * \n * <p>The XML schema definition can be found here: \n * http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd</p>\n * \n * <p>\n * The periodically scanning of files for changes is not currently supported in a \n * clustered environment.\n * </p>\n * \n * <p>\n * If using this plugin with JobStoreCMT, be sure to set the\n * plugin property <em>wrapInUserTransaction</em> to true.  Also, if you have a \n * positive <em>scanInterval</em> be sure to set \n * <em>org.quartz.scheduler.wrapJobExecutionInUserTransaction</em> to true.\n * </p>\n * \n * @see org.quartz.xml.XMLSchedulingDataProcessor\n * \n * @author James House\n * @author Pierre Awaragi\n * @author pl47ypus\n */\npublic class XMLSchedulingDataProcessorPlugin \n    extends SchedulerPluginWithUserTransactionSupport \n    implements FileScanListener {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    private static final int MAX_JOB_TRIGGER_NAME_LEN = 80;\n    private static final String JOB_INITIALIZATION_PLUGIN_NAME = \"JobSchedulingDataLoaderPlugin\";\n    private static final String FILE_NAME_DELIMITERS = \",\";\n    \n    private boolean failOnFileNotFound = true;\n\n    private String fileNames = XMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME;\n\n    // Populated by initialization\n    private final Map<String, JobFile> jobFiles = new LinkedHashMap<>();\n\n    private long scanInterval = 0; \n    \n    boolean started = false;\n    \n    protected ClassLoadHelper classLoadHelper = null;\n\n    private final Set<String> jobTriggerNameSet = new HashSet<>();\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public XMLSchedulingDataProcessorPlugin() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Comma separated list of file names (with paths) to the XML files that should be read.\n     */\n    public String getFileNames() {\n        return fileNames;\n    }\n\n    /**\n     * The file name (and path) to the XML file that should be read.\n     */\n    public void setFileNames(String fileNames) {\n        this.fileNames = fileNames;\n    }\n    \n    /**\n     * The interval (in seconds) at which to scan for changes to the file.  \n     * If the file has been changed, it is re-loaded and parsed.   The default \n     * value for the interval is 0, which disables scanning.\n     * \n     * @return Returns the scanInterval.\n     */\n    public long getScanInterval() {\n        return scanInterval / 1000;\n    }\n\n    /**\n     * The interval (in seconds) at which to scan for changes to the file.  \n     * If the file has been changed, it is re-loaded and parsed.   The default \n     * value for the interval is 0, which disables scanning.\n     * \n     * @param scanInterval The scanInterval to set.\n     */\n    public void setScanInterval(long scanInterval) {\n        this.scanInterval = scanInterval * 1000;\n    }\n    \n    /**\n     * Whether or not initialization of the plugin should fail (throw an\n     * exception) if the file cannot be found. Default is <code>true</code>.\n     */\n    public boolean isFailOnFileNotFound() {\n        return failOnFileNotFound;\n    }\n\n    /**\n     * Whether or not initialization of the plugin should fail (throw an\n     * exception) if the file cannot be found. Default is <code>true</code>.\n     */\n    public void setFailOnFileNotFound(boolean failOnFileNotFound) {\n        this.failOnFileNotFound = failOnFileNotFound;\n    }\n    \n     /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * SchedulerPlugin Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called during creation of the <code>Scheduler</code> in order to give\n     * the <code>SchedulerPlugin</code> a chance to initialize.\n     * </p>\n     * \n     * @throws org.quartz.SchedulerConfigException\n     *           if there is an error initializing.\n     */\n    public void initialize(String name, final Scheduler scheduler, ClassLoadHelper schedulerFactoryClassLoadHelper)\n        throws SchedulerException {\n        super.initialize(name, scheduler);\n        this.classLoadHelper = schedulerFactoryClassLoadHelper;\n        \n        getLog().info(\"Registering Quartz Job Initialization Plug-in.\");\n        \n        // Create JobFile objects\n        StringTokenizer stok = new StringTokenizer(fileNames, FILE_NAME_DELIMITERS);\n        while (stok.hasMoreTokens()) {\n            final String fileName = stok.nextToken();\n            final JobFile jobFile = new JobFile(fileName);\n            jobFiles.put(fileName, jobFile);         \n        }\n    }\n\n    \n    @Override\n    public void start(UserTransaction userTransaction) {\n        try {\n            if (!jobFiles.isEmpty()) {\n                \n                if (scanInterval > 0) {\n                    getScheduler().getContext().put(JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName(), this);\n                }\n\n                Iterator<JobFile> iterator = jobFiles.values().iterator();\n                while (iterator.hasNext()) {\n                    JobFile jobFile = iterator.next();\n\n                    if (scanInterval > 0) {\n                        String jobTriggerName = buildJobTriggerName(jobFile.getFileBasename());\n                        TriggerKey tKey = new TriggerKey(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME);\n\n                        // remove preexisting job/trigger, if any\n                        getScheduler().unscheduleJob(tKey);\n\n                        JobDetail job = newJob().withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME).ofType(FileScanJob.class)\n                            .usingJobData(FileScanJob.FILE_NAME, jobFile.getFileName())\n                            .usingJobData(FileScanJob.FILE_SCAN_LISTENER_NAME, JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName())\n                            .build();\n\n                        SimpleTrigger trig = newTrigger().withIdentity(tKey).withSchedule(\n                                simpleSchedule().repeatForever().withIntervalInMilliseconds(scanInterval))\n                                .forJob(job)\n                                .build();\n\n                        getScheduler().scheduleJob(job, trig);\n                        getLog().debug(\"Scheduled file scan job for data file: {}, at interval: {}\", jobFile.getFileName(), scanInterval);\n                    }\n\n                    processFile(jobFile);\n                }\n            }\n        } catch(SchedulerException se) {\n            getLog().error(\"Error starting background-task for watching jobs file.\", se);\n        } finally {\n            started = true;\n        }\n    }\n    \n    /**\n     * Helper method for generating unique job/trigger name for the  \n     * file scanning jobs (one per FileJob).  The unique names are saved\n     * in jobTriggerNameSet.\n     */\n    private String buildJobTriggerName(\n            String fileBasename) {\n        // Name w/o collisions will be prefix + _ + filename (with '.' of filename replaced with '_')\n        // For example: JobInitializationPlugin_jobInitializer_myjobs_xml\n        String jobTriggerName = JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName() + '_' + fileBasename.replace('.', '_');\n        \n        // If name is too long (DB column is 80 chars), then truncate to max length\n        if (jobTriggerName.length() > MAX_JOB_TRIGGER_NAME_LEN) {\n            jobTriggerName = jobTriggerName.substring(0, MAX_JOB_TRIGGER_NAME_LEN);\n        }\n        \n        // Make sure this name is unique in case the same file name under different\n        // directories is being checked, or had a naming collision due to length truncation.\n        // If there is a conflict, keep incrementing a _# suffix on the name (being sure\n        // not to get too long), until we find a unique name.\n        int currentIndex = 1;\n        while (!jobTriggerNameSet.add(jobTriggerName)) {\n            // If not our first time through, then strip off old numeric suffix\n            if (currentIndex > 1) {\n                jobTriggerName = jobTriggerName.substring(0, jobTriggerName.lastIndexOf('_'));\n            }\n\n            String numericSuffix = \"_\" + currentIndex++;\n\n            // If the numeric suffix would make the name too long, then make room for it.\n            if (jobTriggerName.length() > (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())) {\n                jobTriggerName = jobTriggerName.substring(0, (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length()));\n            }\n\n            jobTriggerName += numericSuffix;\n        }\n        \n        return jobTriggerName;\n    }\n    \n    /**\n     * Overridden to ignore <em>wrapInUserTransaction</em> because shutdown()\n     * does not interact with the <code>Scheduler</code>. \n     */\n    @Override\n    public void shutdown() {\n        // Since we have nothing to do, override base shutdown so don't\n        // get extraneous UserTransactions.\n    }\n\n    private void processFile(JobFile jobFile) {\n        if (jobFile == null || !jobFile.getFileFound()) {\n            return;\n        }\n\n\n        try {\n            XMLSchedulingDataProcessor processor = \n                new XMLSchedulingDataProcessor(this.classLoadHelper);\n            \n            processor.addJobGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);\n            processor.addTriggerGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);\n            \n            processor.processFileAndScheduleJobs(\n                    jobFile.getFileName(), \n                    jobFile.getFileName(), // systemId \n                    getScheduler());\n        } catch (Exception e) {\n            getLog().error(\"Error scheduling jobs: {}\", e.getMessage(), e);\n        }\n    }\n    \n    public void processFile(String filePath) {\n        processFile((JobFile)jobFiles.get(filePath));\n    }\n\n    /** \n     * @see org.quartz.jobs.FileScanListener#fileUpdated(java.lang.String)\n     */\n    public void fileUpdated(String fileName) {\n        if (started) {\n            processFile(fileName);\n        }\n    }\n    \n    class JobFile {\n        private final String fileName;\n\n        // These are set by initialize()\n        private String filePath;\n        private String fileBasename;\n        private boolean fileFound;\n\n        protected JobFile(String fileName) throws SchedulerException {\n            this.fileName = fileName;\n            initialize();\n        }\n        \n        protected String getFileName() {\n            return fileName;\n        }\n        \n        protected boolean getFileFound() {\n            return fileFound;\n        }\n\n        protected String getFilePath() {\n            return filePath;\n        }\n        \n        protected String getFileBasename() {\n            return fileBasename;\n        }\n                \n        private void initialize() throws SchedulerException {\n            InputStream f = null;\n            try {\n                String furl = null;\n                \n                File file = new File(getFileName()); // files in filesystem\n                if (!file.exists()) {\n                    URL url = classLoadHelper.getResource(getFileName());\n                    if(url != null) {\n                        furl = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8);\n                        file = new File(furl); \n                        try {\n                            f = url.openStream();\n                        } catch (IOException ignore) {\n                            // Swallow the exception\n                        }\n                    }        \n                } else {\n                    try {              \n                        f = new java.io.FileInputStream(file);\n                    }catch (FileNotFoundException e) {\n                        // ignore\n                    }\n                }\n                \n                if (f == null) {\n                    if (isFailOnFileNotFound()) {\n                        throw new SchedulerException(\n                            \"File named '\" + getFileName() + \"' does not exist.\");\n                    } else {\n                        getLog().warn(\"File named '{}' does not exist.\", getFileName());\n                    }\n                } else {\n                    fileFound = true;\n                }\n                filePath = (furl != null) ? furl : file.getAbsolutePath();\n                fileBasename = file.getName();\n            } finally {\n                try {\n                    if (f != null) {\n                        f.close();\n                    }\n                } catch (IOException ioe) {\n                    getLog().warn(\"Error closing jobs file {}\", getFileName(), ioe);\n                }\n            }\n        }\n    }\n}\n\n// EOF\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/CascadingClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport java.util.LinkedList;\nimport java.net.URL;\nimport java.io.InputStream;\n\nimport org.quartz.spi.ClassLoadHelper;\n\n/**\n * A <code>ClassLoadHelper</code> uses all of the <code>ClassLoadHelper</code>\n * types that are found in this package in its attempts to load a class, when\n * one scheme is found to work, it is promoted to the scheme that will be used\n * first the next time a class is loaded (in order to improve performance).\n * \n * <p>\n * This approach is used because of the wide variance in class loader behavior\n * between the various environments in which Quartz runs (e.g. disparate \n * application servers, stand-alone, mobile devices, etc.).  Because of this\n * disparity, Quartz ran into difficulty with a one class-load style fits-all \n * design.  Thus, this class loader finds the approach that works, then \n * 'remembers' it.  \n * </p>\n * \n * @see org.quartz.spi.ClassLoadHelper\n * @see org.quartz.simpl.LoadingLoaderClassLoadHelper\n * @see org.quartz.simpl.SimpleClassLoadHelper\n * @see org.quartz.simpl.ThreadContextClassLoadHelper\n * @see org.quartz.simpl.InitThreadContextClassLoadHelper\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic class CascadingClassLoadHelper implements ClassLoadHelper {\n\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private LinkedList<ClassLoadHelper> loadHelpers;\n\n    private ClassLoadHelper bestCandidate;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    public void initialize() {\n        loadHelpers = new LinkedList<>();\n\n        loadHelpers.add(new LoadingLoaderClassLoadHelper());\n        loadHelpers.add(new SimpleClassLoadHelper());\n        loadHelpers.add(new ThreadContextClassLoadHelper());\n        loadHelpers.add(new InitThreadContextClassLoadHelper());\n        \n        for(ClassLoadHelper loadHelper: loadHelpers) {\n            loadHelper.initialize();\n        }\n    }\n\n    /**\n     * Return the class with the given name.\n     */\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        if (bestCandidate != null) {\n            try {\n                return bestCandidate.loadClass(name);\n            } catch (Throwable t) {\n                bestCandidate = null;\n            }\n        }\n\n        Throwable throwable = null;\n\n        for (ClassLoadHelper helper : loadHelpers) {\n            try {\n                Class<?> clazz = helper.loadClass(name);\n                bestCandidate = helper;\n                return clazz;\n            } catch (Throwable t) {\n                throwable = t;\n            }\n        }\n\n        if (throwable instanceof ClassNotFoundException) {\n            throw (ClassNotFoundException) throwable;\n        } else {\n            throw new ClassNotFoundException( String.format( \"Unable to load class %s by any known loaders.\", name), throwable);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Class<? extends T> loadClass(String name, Class<T> clazz)\n            throws ClassNotFoundException {\n        return (Class<? extends T>) loadClass(name);\n    }\n    \n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    public URL getResource(String name) {\n\n        URL result = null;\n\n        if (bestCandidate != null) {\n            result = bestCandidate.getResource(name);\n            if(result == null) {\n              bestCandidate = null;\n            }\n            else {\n                return result;\n            }\n        }\n\n        ClassLoadHelper loadHelper = null;\n\n        for (ClassLoadHelper helper : loadHelpers) {\n            loadHelper = helper;\n\n            result = loadHelper.getResource(name);\n            if (result != null) {\n                break;\n            }\n        }\n\n        bestCandidate = loadHelper;\n        return result;\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    public InputStream getResourceAsStream(String name) {\n\n        InputStream result = null;\n\n        if (bestCandidate != null) {\n            result = bestCandidate.getResourceAsStream(name);\n            if(result == null) {\n                bestCandidate = null;\n            }\n            else {\n                return result;\n            }\n        }\n\n        ClassLoadHelper loadHelper = null;\n\n        for (ClassLoadHelper helper : loadHelpers) {\n            loadHelper = helper;\n\n            result = loadHelper.getResourceAsStream(name);\n            if (result != null) {\n                break;\n            }\n        }\n\n        bestCandidate = loadHelper;\n        return result;\n    }\n\n    /**\n     * Enable sharing of the \"best\" class-loader with 3rd party.\n     *\n     * @return the class-loader user be the helper.\n     */\n    public ClassLoader getClassLoader() {\n        return (this.bestCandidate == null) ?\n                Thread.currentThread().getContextClassLoader() :\n                this.bestCandidate.getClassLoader();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/HostnameInstanceIdGenerator.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.simpl;\n\nimport java.net.InetAddress;\n\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.InstanceIdGenerator;\n\n/**\n * <p>\n * <code>InstanceIdGenerator</code> that names the scheduler instance using \n * just the machine hostname.\n * </p>\n * \n * <p>\n * This class is useful when you know that your scheduler instance will be the \n * only one running on a particular machine.  Each time the scheduler is \n * restarted, it will get the same instance id as long as the machine is not \n * renamed.\n * </p>\n * \n * @see InstanceIdGenerator\n * @see SimpleInstanceIdGenerator\n */\npublic class HostnameInstanceIdGenerator implements InstanceIdGenerator {\n    public String generateInstanceId() throws SchedulerException {\n        try {\n            return InetAddress.getLocalHost().getHostName();\n        } catch (Exception e) {\n            throw new SchedulerException(\"Couldn't get host name!\", e);\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/InitThreadContextClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.quartz.spi.ClassLoadHelper;\n\nimport java.net.URL;\nimport java.io.InputStream;\n\n/**\n * A <code>ClassLoadHelper</code> that uses either the context class loader\n * of the thread that initialized Quartz.\n * \n * @see org.quartz.spi.ClassLoadHelper\n * @see org.quartz.simpl.ThreadContextClassLoadHelper\n * @see org.quartz.simpl.SimpleClassLoadHelper\n * @see org.quartz.simpl.CascadingClassLoadHelper\n * @see org.quartz.simpl.LoadingLoaderClassLoadHelper\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic class InitThreadContextClassLoadHelper implements ClassLoadHelper {\n\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private ClassLoader initClassLoader;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    public void initialize() {\n        initClassLoader = Thread.currentThread().getContextClassLoader();\n    }\n\n    /**\n     * Return the class with the given name.\n     */\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        return initClassLoader.loadClass(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Class<? extends T> loadClass(String name, Class<T> clazz)\n            throws ClassNotFoundException {\n        return (Class<? extends T>) loadClass(name);\n    }\n    \n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    public URL getResource(String name) {\n        return initClassLoader.getResource(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    public InputStream getResourceAsStream(String name) {\n        return initClassLoader.getResourceAsStream(name);\n    }\n\n    /**\n     * Enable sharing of the class-loader with 3rd party.\n     *\n     * @return the class-loader user be the helper.\n     */\n    public ClassLoader getClassLoader() {\n        return this.initClassLoader;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/LoadingLoaderClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.quartz.spi.ClassLoadHelper;\n\nimport java.net.URL;\nimport java.io.InputStream;\n\n/**\n * A <code>ClassLoadHelper</code> that uses either the loader of it's own\n * class (<code>this.getClass().getClassLoader().loadClass( .. )</code>).\n * \n * @see org.quartz.spi.ClassLoadHelper\n * @see org.quartz.simpl.InitThreadContextClassLoadHelper\n * @see org.quartz.simpl.SimpleClassLoadHelper\n * @see org.quartz.simpl.CascadingClassLoadHelper\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic class LoadingLoaderClassLoadHelper implements ClassLoadHelper {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    public void initialize() {\n    }\n\n    /**\n     * Return the class with the given name.\n     */\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        return getClassLoader().loadClass(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Class<? extends T> loadClass(String name, Class<T> clazz)\n            throws ClassNotFoundException {\n        return (Class<? extends T>) loadClass(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    public URL getResource(String name) {\n        return getClassLoader().getResource(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    public InputStream getResourceAsStream(String name) {\n        return getClassLoader().getResourceAsStream(name);\n    }\n\n    /**\n     * Enable sharing of the class-loader with 3rd party.\n     *\n     * @return the class-loader user be the helper.\n     */\n    public ClassLoader getClassLoader() {\n        return this.getClass().getClassLoader();\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/PropertySettingJobFactory.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.simpl;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.PropertyDescriptor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.TriggerFiredBundle;\n\n\n\n/**\n * A JobFactory that instantiates the Job instance (using the default no-arg\n * constructor, or more specifically: <code>class.newInstance()</code>), and\n * then attempts to set all values from the <code>SchedulerContext</code> and\n * the <code>JobExecutionContext</code>'s merged <code>JobDataMap</code> onto \n * bean properties of the <code>Job</code>.\n * \n * <p>Set the warnIfPropertyNotFound property to true if you'd like noisy logging in\n * the case of values in the JobDataMap not mapping to properties on your Job\n * class.  This may be useful for troubleshooting typos of property names, etc.\n * but very noisy if you regularly (and purposely) have extra things in your\n * JobDataMap.</p>\n * \n * <p>Also of possible interest is the throwIfPropertyNotFound property which\n * will throw exceptions on unmatched JobDataMap keys.</p>\n * \n * @see org.quartz.spi.JobFactory\n * @see SimpleJobFactory\n * @see SchedulerContext\n * @see org.quartz.JobExecutionContext#getMergedJobDataMap()\n * @see #setWarnIfPropertyNotFound(boolean)\n * @see #setThrowIfPropertyNotFound(boolean)\n * \n * @author jhouse\n */\npublic class PropertySettingJobFactory extends SimpleJobFactory {\n    private boolean warnIfNotFound = false;\n    private boolean throwIfNotFound = false;\n    \n    @Override\n    public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {\n\n        Job job = super.newJob(bundle, scheduler);\n        \n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.putAll(scheduler.getContext());\n        jobDataMap.putAll(bundle.getJobDetail().getJobDataMap());\n        jobDataMap.putAll(bundle.getTrigger().getJobDataMap());\n\n        setBeanProps(job, jobDataMap);\n        \n        return job;\n    }\n    \n    protected void setBeanProps(Object obj, JobDataMap data) throws SchedulerException {\n\n        BeanInfo bi = null;\n        try {\n            bi = Introspector.getBeanInfo(obj.getClass());\n        } catch (IntrospectionException e) {\n            handleError(\"Unable to introspect Job class.\", e);\n        }\n        \n        PropertyDescriptor[] propDescs = bi.getPropertyDescriptors();\n        \n        // Get the wrapped entry set so don't have to incur overhead of wrapping for\n        // dirty flag checking since this is read only access\n        for (Map.Entry<String, Object> stringObjectEntry : data.getWrappedMap().entrySet()) {\n\n            String name = (String) ((Map.Entry<?, ?>) stringObjectEntry).getKey();\n            String c = name.substring(0, 1).toUpperCase(Locale.US);\n            String methName = \"set\" + c + name.substring(1);\n\n            java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs);\n\n            Class<?> paramType = null;\n            Object o = null;\n\n            try {\n                if (setMeth == null) {\n                    handleError(\n                            \"No setter on Job class \" + obj.getClass().getName() +\n                                    \" for property '\" + name + \"'\");\n                    continue;\n                }\n\n                paramType = setMeth.getParameterTypes()[0];\n                o = ((Map.Entry<?, ?>) stringObjectEntry).getValue();\n\n                Object parm = null;\n                if (paramType.isPrimitive()) {\n                    if (o == null) {\n                        handleError(\n                                \"Cannot set primitive property '\" + name +\n                                        \"' on Job class \" + obj.getClass().getName() +\n                                        \" to null.\");\n                        continue;\n                    }\n\n                    if (paramType.equals(int.class)) {\n                        if (o instanceof String) {\n                            parm = Integer.valueOf((String) o);\n                        } else if (o instanceof Integer) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(long.class)) {\n                        if (o instanceof String) {\n                            parm = Long.valueOf((String) o);\n                        } else if (o instanceof Long) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(float.class)) {\n                        if (o instanceof String) {\n                            parm = Float.valueOf((String) o);\n                        } else if (o instanceof Float) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(double.class)) {\n                        if (o instanceof String) {\n                            parm = Double.valueOf((String) o);\n                        } else if (o instanceof Double) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(boolean.class)) {\n                        if (o instanceof String) {\n                            parm = Boolean.valueOf((String) o);\n                        } else if (o instanceof Boolean) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(byte.class)) {\n                        if (o instanceof String) {\n                            parm = Byte.valueOf((String) o);\n                        } else if (o instanceof Byte) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(short.class)) {\n                        if (o instanceof String) {\n                            parm = Short.valueOf((String) o);\n                        } else if (o instanceof Short) {\n                            parm = o;\n                        }\n                    } else if (paramType.equals(char.class)) {\n                        if (o instanceof String) {\n                            String str = (String) o;\n                            if (str.length() == 1) {\n                                parm = str.charAt(0);\n                            }\n                        } else if (o instanceof Character) {\n                            parm = o;\n                        }\n                    }\n                } else if ((o != null) && (paramType.isAssignableFrom(o.getClass()))) {\n                    parm = o;\n                }\n\n                // If the parameter wasn't originally null, but we didn't find a \n                // matching parameter, then we are stuck.\n                if ((o != null) && (parm == null)) {\n                    handleError(\n                            \"The setter on Job class \" + obj.getClass().getName() +\n                                    \" for property '\" + name +\n                                    \"' expects a \" + paramType +\n                                    \" but was given \" + o.getClass().getName());\n                    continue;\n                }\n\n                setMeth.invoke(obj, new Object[]{parm});\n            } catch (IllegalArgumentException e) {\n                handleError(\n                        \"The setter on Job class \" + obj.getClass().getName() +\n                                \" for property '\" + name +\n                                \"' expects a \" + paramType +\n                                \" but was given \" + o.getClass().getName(), e);\n            } catch (IllegalAccessException e) {\n                handleError(\n                        \"The setter on Job class \" + obj.getClass().getName() +\n                                \" for property '\" + name +\n                                \"' could not be accessed.\", e);\n            } catch (InvocationTargetException e) {\n                handleError(\n                        \"The setter on Job class \" + obj.getClass().getName() +\n                                \" for property '\" + name +\n                                \"' could not be invoked.\", e);\n            }\n        }\n    }\n     \n    private void handleError(String message) throws SchedulerException {\n        handleError(message, null);\n    }\n    \n    private void handleError(String message, Exception e) throws SchedulerException {\n        if (isThrowIfPropertyNotFound()) {\n            throw new SchedulerException(message, e);\n        }\n        \n        if (isWarnIfPropertyNotFound()) {\n            if (e == null) {\n                getLog().warn(message);\n            } else {\n                getLog().warn(message, e);\n            }\n        }\n    }\n    \n    private java.lang.reflect.Method getSetMethod(String name,\n            PropertyDescriptor[] props) {\n        for (PropertyDescriptor prop : props) {\n            java.lang.reflect.Method wMeth = prop.getWriteMethod();\n\n            if (wMeth == null) {\n                continue;\n            }\n\n            if (wMeth.getParameterTypes().length != 1) {\n                continue;\n            }\n\n            if (wMeth.getName().equals(name)) {\n                return wMeth;\n            }\n        }\n        \n        return null;\n    }\n\n    /**\n     * Whether the JobInstantiation should fail and throw and exception if\n     * a key (name) and value (type) found in the JobDataMap does not \n     * correspond to a property setter on the Job class.\n     *  \n     * @return Returns the throwIfNotFound.\n     */\n    public boolean isThrowIfPropertyNotFound() {\n        return throwIfNotFound;\n    }\n\n    /**\n     * Whether the JobInstantiation should fail and throw and exception if\n     * a key (name) and value (type) found in the JobDataMap does not \n     * correspond to a property setter on the Job class.\n     *  \n     * @param throwIfNotFound defaults to <code>false</code>.\n     */\n    public void setThrowIfPropertyNotFound(boolean throwIfNotFound) {\n        this.throwIfNotFound = throwIfNotFound;\n    }\n\n    /**\n     * Whether a warning should be logged if\n     * a key (name) and value (type) found in the JobDataMap does not \n     * correspond to a property setter on the Job class.\n     *  \n     * @return Returns the warnIfNotFound.\n     */\n    public boolean isWarnIfPropertyNotFound() {\n        return warnIfNotFound;\n    }\n\n    /**\n     * Whether a warning should be logged if\n     * a key (name) and value (type) found in the JobDataMap does not \n     * correspond to a property setter on the Job class.\n     *  \n     * @param warnIfNotFound defaults to <code>true</code>.\n     */\n    public void setWarnIfPropertyNotFound(boolean warnIfNotFound) {\n        this.warnIfNotFound = warnIfNotFound;\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/RAMJobStore.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.Map.Entry;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.ObjectAlreadyExistsException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.Trigger.TriggerTimeComparator;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.matchers.StringMatcher;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.SchedulerSignaler;\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.quartz.spi.TriggerFiredResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This class implements a <code>{@link org.quartz.spi.JobStore}</code> that\n * utilizes RAM as its storage device.\n * </p>\n * \n * <p>\n * As you should know, the ramification of this is that access is extremely\n * fast, but the data is completely volatile - therefore this <code>JobStore</code>\n * should not be used if true persistence between program shutdowns is\n * required.\n * </p>\n * \n * @author James House\n * @author Sharada Jambula\n * @author Eric Mueller\n */\npublic class RAMJobStore implements JobStore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected final HashMap<JobKey, JobWrapper> jobsByKey = new HashMap<>(1000);\n\n    protected final HashMap<TriggerKey, TriggerWrapper> triggersByKey = new HashMap<>(1000);\n\n    protected final HashMap<String, HashMap<JobKey, JobWrapper>> jobsByGroup = new HashMap<>(25);\n\n    protected final HashMap<String, HashMap<TriggerKey, TriggerWrapper>> triggersByGroup = new HashMap<>(25);\n\n    protected final TreeSet<TriggerWrapper> timeTriggers = new TreeSet<>(new TriggerWrapperComparator());\n\n    protected final HashMap<String, Calendar> calendarsByName = new HashMap<>(25);\n\n    protected final Map<JobKey, List<TriggerWrapper>> triggersByJob = new HashMap<>(1000);\n\n    protected final Object lock = new Object();\n\n    protected final HashSet<String> pausedTriggerGroups = new HashSet<>();\n\n    protected final HashSet<String> pausedJobGroups = new HashSet<>();\n\n    protected final HashSet<JobKey> blockedJobs = new HashSet<>();\n    \n    protected long misfireThreshold = 5000L;\n\n    protected SchedulerSignaler signaler;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a new <code>RAMJobStore</code>.\n     * </p>\n     */\n    public RAMJobStore() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler before the <code>JobStore</code> is\n     * used, in order to give the it a chance to initialize.\n     * </p>\n     */\n    public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler schedSignaler) {\n\n        this.signaler = schedSignaler;\n\n        getLog().info(\"RAMJobStore initialized.\");\n    }\n\n    public void schedulerStarted() {\n        // nothing to do\n    }\n\n    public void schedulerPaused() {\n        // nothing to do\n    }\n    \n    public void schedulerResumed() {\n        // nothing to do\n    }\n    \n    public long getMisfireThreshold() {\n        return misfireThreshold;\n    }\n\n    /**\n     * The number of milliseconds by which a trigger must have missed its\n     * next-fire-time, in order for it to be considered \"misfired\" and thus\n     * have its misfire instruction applied.\n     * \n     * @param misfireThreshold the new misfire threshold\n     */\n    @SuppressWarnings(\"UnusedDeclaration\")\n    public void setMisfireThreshold(long misfireThreshold) {\n        if (misfireThreshold < 1) {\n            throw new IllegalArgumentException(\"Misfire threshold must be larger than 0\");\n        }\n        this.misfireThreshold = misfireThreshold;\n    }\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * it should free up all of it's resources because the scheduler is\n     * shutting down.\n     * </p>\n     */\n    public void shutdown() {\n    }\n\n    public boolean supportsPersistence() {\n        return false;\n    }\n\n    /**\n     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws JobPersistenceException\n     */\n    public void clearAllSchedulingData() throws JobPersistenceException {\n\n        synchronized (lock) {\n            // unschedule jobs (delete triggers)\n            List<String> lst = getTriggerGroupNames();\n            for (String group: lst) {\n                Set<TriggerKey> keys = getTriggerKeys(GroupMatcher.triggerGroupEquals(group));\n                for (TriggerKey key: keys) {\n                    removeTrigger(key);\n                }\n            }\n            // delete jobs\n            lst = getJobGroupNames();\n            for (String group: lst) {\n                Set<JobKey> keys = getJobKeys(GroupMatcher.jobGroupEquals(group));\n                for (JobKey key: keys) {\n                    removeJob(key);\n                }\n            }\n            // delete calendars\n            lst = getCalendarNames();\n            for(String name: lst) {\n                removeCalendar(name);\n            }\n        }\n    }\n    \n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     * \n     * @param newJob\n     *          The <code>JobDetail</code> to be stored.\n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists.\n     */\n    public void storeJobAndTrigger(JobDetail newJob,\n            OperableTrigger newTrigger) throws JobPersistenceException {\n        storeJob(newJob, false);\n        storeTrigger(newTrigger, false);\n    }\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.Job}</code>.\n     * </p>\n     * \n     * @param newJob\n     *          The <code>Job</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Job</code> existing in the\n     *          <code>JobStore</code> with the same name and group should be\n     *          over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     */\n    public void storeJob(JobDetail newJob,\n            boolean replaceExisting) throws ObjectAlreadyExistsException {\n        JobWrapper jw = new JobWrapper((JobDetail)newJob.clone());\n\n        boolean repl = false;\n\n        synchronized (lock) {\n            if (jobsByKey.get(jw.key) != null) {\n                if (!replaceExisting) {\n                    throw new ObjectAlreadyExistsException(newJob);\n                }\n                repl = true;\n            }\n\n            if (!repl) {\n                // get job group\n                HashMap<JobKey, JobWrapper> grpMap = jobsByGroup.computeIfAbsent(newJob.getKey().getGroup(), k -> new HashMap<>(100));\n                // add to jobs by group\n                grpMap.put(newJob.getKey(), jw);\n                // add to jobs by FQN map\n                jobsByKey.put(jw.key, jw);\n            } else {\n                // update job detail\n                JobWrapper orig = jobsByKey.get(jw.key);\n                orig.jobDetail = jw.jobDetail; // already cloned\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Job}</code> with the given\n     * name, and any <code>{@link org.quartz.Trigger}</code> s that reference\n     * it.\n     * </p>\n     *\n     * @return <code>true</code> if a <code>Job</code> with the given name and\n     *         group was found and removed from the store.\n     */\n    public boolean removeJob(JobKey jobKey) {\n\n        boolean found = false;\n\n        synchronized (lock) {\n            List<OperableTrigger> triggersOfJob = getTriggersForJob(jobKey);\n            for (OperableTrigger trig: triggersOfJob) {\n                this.removeTrigger(trig.getKey());\n                found = true;\n            }\n            \n            found = (jobsByKey.remove(jobKey) != null) | found;\n            if (found) {\n\n                HashMap<JobKey, JobWrapper> grpMap = jobsByGroup.get(jobKey.getGroup());\n                if (grpMap != null) {\n                    grpMap.remove(jobKey);\n                    if (grpMap.isEmpty()) {\n                        jobsByGroup.remove(jobKey.getGroup());\n                    }\n                }\n            }\n        }\n\n        return found;\n    }\n\n    public boolean removeJobs(List<JobKey> jobKeys)\n            throws JobPersistenceException {\n        boolean allFound = true;\n\n        synchronized (lock) {\n            for(JobKey key: jobKeys)\n                allFound = removeJob(key) && allFound;\n        }\n\n        return allFound;\n    }\n\n    public boolean removeTriggers(List<TriggerKey> triggerKeys)\n            throws JobPersistenceException {\n        boolean allFound = true;\n\n        synchronized (lock) {\n            for(TriggerKey key: triggerKeys)\n                allFound = removeTrigger(key) && allFound;\n        }\n\n        return allFound;\n    }\n\n    public void storeJobsAndTriggers(\n            Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace)\n            throws JobPersistenceException {\n\n        synchronized (lock) {\n            // make sure there are no collisions...\n            if(!replace) {\n                for(Entry<JobDetail, Set<? extends Trigger>> e: triggersAndJobs.entrySet()) {\n                    if(checkExists(e.getKey().getKey()))\n                        throw new ObjectAlreadyExistsException(e.getKey());\n                    for(Trigger trigger: e.getValue()) {\n                        if(checkExists(trigger.getKey()))\n                            throw new ObjectAlreadyExistsException(trigger);\n                    }\n                }\n            }\n            // do bulk add...\n            for(Entry<JobDetail, Set<? extends Trigger>> e: triggersAndJobs.entrySet()) {\n                storeJob(e.getKey(), true);\n                for(Trigger trigger: e.getValue()) {\n                    storeTrigger((OperableTrigger) trigger, true);\n                }\n            }\n        }\n        \n    }\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     *\n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Trigger</code> existing in\n     *          the <code>JobStore</code> with the same name and group should\n     *          be over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Trigger</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     *\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    public void storeTrigger(OperableTrigger newTrigger,\n            boolean replaceExisting) throws JobPersistenceException {\n        TriggerWrapper tw = new TriggerWrapper((OperableTrigger)newTrigger.clone());\n\n        synchronized (lock) {\n            if (triggersByKey.get(tw.key) != null) {\n                if (!replaceExisting) {\n                    throw new ObjectAlreadyExistsException(newTrigger);\n                }\n    \n                removeTrigger(newTrigger.getKey(), false);\n            }\n    \n            if (retrieveJob(newTrigger.getJobKey()) == null) {\n                throw new JobPersistenceException(\"The job (\"\n                        + newTrigger.getJobKey()\n                        + \") referenced by the trigger does not exist.\");\n            }\n\n            // add to triggers by job\n            List<TriggerWrapper> jobList = triggersByJob.computeIfAbsent(tw.jobKey, k -> new ArrayList<>(1));\n            jobList.add(tw);\n            \n            // add to triggers by group\n            HashMap<TriggerKey, TriggerWrapper> grpMap = triggersByGroup.computeIfAbsent(newTrigger.getKey().getGroup(), k -> new HashMap<>(100));\n            grpMap.put(newTrigger.getKey(), tw);\n            // add to triggers by FQN map\n            triggersByKey.put(tw.key, tw);\n\n            if (pausedTriggerGroups.contains(newTrigger.getKey().getGroup())\n                    || pausedJobGroups.contains(newTrigger.getJobKey().getGroup())) {\n                tw.state = TriggerWrapper.STATE_PAUSED;\n                if (blockedJobs.contains(tw.jobKey)) {\n                    tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;\n                }\n            } else if (blockedJobs.contains(tw.jobKey)) {\n                tw.state = TriggerWrapper.STATE_BLOCKED;\n            } else {\n                timeTriggers.add(tw);\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given name.\n     * </p>\n     *\n     * @return <code>true</code> if a <code>Trigger</code> with the given\n     *         name and group was found and removed from the store.\n     */\n    public boolean removeTrigger(TriggerKey triggerKey) {\n        return removeTrigger(triggerKey, true);\n    }\n    \n    private boolean removeTrigger(TriggerKey key, boolean removeOrphanedJob) {\n\n        boolean found;\n\n        synchronized (lock) {\n            // remove from triggers by FQN map\n            TriggerWrapper tw = triggersByKey.remove(key);\n            found = tw != null;\n            if (found) {\n                // remove from triggers by group\n                HashMap<TriggerKey, TriggerWrapper> grpMap = triggersByGroup.get(key.getGroup());\n                if (grpMap != null) {\n                    grpMap.remove(key);\n                    if (grpMap.isEmpty()) {\n                        triggersByGroup.remove(key.getGroup());\n                    }\n                }\n                //remove from triggers by job\n                List<TriggerWrapper> jobList = triggersByJob.get(tw.jobKey);\n                if(jobList != null) {\n                    jobList.remove(tw);\n                    if(jobList.isEmpty()) {\n                        triggersByJob.remove(tw.jobKey);\n                    }\n                }\n               \n                timeTriggers.remove(tw);\n\n                if (removeOrphanedJob) {\n                    JobWrapper jw = jobsByKey.get(tw.jobKey);\n                    List<OperableTrigger> trigs = getTriggersForJob(tw.jobKey);\n                    if ((trigs == null || trigs.isEmpty()) && !jw.jobDetail.isDurable()) {\n                        if (removeJob(jw.key)) {\n                            signaler.notifySchedulerListenersJobDeleted(jw.key);\n                        }\n                    }\n                }\n            }\n        }\n\n        return found;\n    }\n\n\n    /**\n     * @see org.quartz.spi.JobStore#replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger)\n     */\n    public boolean replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) throws JobPersistenceException {\n\n        boolean found;\n\n        synchronized (lock) {\n            // remove from triggers by FQN map\n            TriggerWrapper tw = triggersByKey.remove(triggerKey);\n            found = (tw != null);\n\n            if (found) {\n\n                if (!tw.getTrigger().getJobKey().equals(newTrigger.getJobKey())) {\n                    throw new JobPersistenceException(\"New trigger is not related to the same job as the old trigger.\");\n                }\n\n                // remove from triggers by group\n                HashMap<TriggerKey, TriggerWrapper> grpMap = triggersByGroup.get(triggerKey.getGroup());\n                if (grpMap != null) {\n                    grpMap.remove(triggerKey);\n                    if (grpMap.isEmpty()) {\n                        triggersByGroup.remove(triggerKey.getGroup());\n                    }\n                }\n                \n                //remove from triggers by job\n                List<TriggerWrapper> jobList = triggersByJob.get(tw.jobKey);\n                if(jobList != null) {\n                    jobList.remove(tw);\n                    if(jobList.isEmpty()) {\n                        triggersByJob.remove(tw.jobKey);\n                    }\n                }\n                \n                timeTriggers.remove(tw);\n\n                try {\n                    storeTrigger(newTrigger, false);\n                } catch(JobPersistenceException jpe) {\n                    storeTrigger(tw.getTrigger(), false); // put previous trigger back...\n                    throw jpe;\n                }\n            }\n        }\n\n        return found;\n    }\n\n    /**\n     * <p>\n     * Retrieve the <code>{@link org.quartz.JobDetail}</code> for the given\n     * <code>{@link org.quartz.Job}</code>.\n     * </p>\n     *\n     * @return The desired <code>Job</code>, or null if there is no match.\n     */\n    public JobDetail retrieveJob(JobKey jobKey) {\n        synchronized(lock) {\n            JobWrapper jw = jobsByKey.get(jobKey);\n            return (jw != null) ? (JobDetail)jw.jobDetail.clone() : null;\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve all the matched <code>{@link org.quartz.JobDetail}</code> for the given\n     * <code>{@link org.quartz.impl.matchers.GroupMatcher}</code>.\n     * </p>\n     *\n     * @return A list of all the matched <code>Job</code>s, or an empty list if there are no matches.\n     */\n    public List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher) {\n        List<JobDetail> outList = null;\n        synchronized (lock) {\n\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            String compareToValue = matcher.getCompareToValue();\n\n            switch(operator) {\n                case EQUALS:\n                    HashMap<JobKey, JobWrapper> grpMap = jobsByGroup.get(compareToValue);\n                    if (grpMap != null) {\n                        outList = new LinkedList<>();\n\n                        for (JobWrapper jw : grpMap.values()) {\n\n                            if (jw != null) {\n                                outList.add(jw.jobDetail);\n                            }\n                        }\n                    }\n                    break;\n\n                default:\n                    for (Map.Entry<String, HashMap<JobKey, JobWrapper>> entry : jobsByGroup.entrySet()) {\n                        if(operator.evaluate(entry.getKey(), compareToValue) && entry.getValue() != null) {\n                            if(outList == null) {\n                                outList = new LinkedList<>();\n                            }\n                            for (JobWrapper jobWrapper : entry.getValue().values()) {\n                                if(jobWrapper != null) {\n                                    outList.add(jobWrapper.jobDetail);\n                                }\n                            }\n                        }\n                    }\n            }\n        }\n\n        return outList == null ? java.util.Collections.emptyList() : outList;\n    }\n\n    public List<OperableTrigger> getTriggersByJobAndTriggerGroup(GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws JobPersistenceException {\n        List<OperableTrigger> matchingTriggers = new ArrayList<>();\n\n        synchronized (lock) {\n            // Get all matching jobs\n            Set<JobKey> matchingJobKeys = getJobKeys(jobMatcher);\n\n            for (JobKey jobKey : matchingJobKeys) {\n                // Get triggers for the job\n                List<OperableTrigger> jobTriggers = getTriggersForJob(jobKey);\n\n                for (OperableTrigger trigger : jobTriggers) {\n\n                    // Check if the trigger matches the trigger group\n                    if (triggerMatcher.getCompareWithOperator().evaluate(trigger.getKey().getGroup(), triggerMatcher.getCompareToValue())) {\n                        matchingTriggers.add(trigger);\n                    }\n                }\n            }\n        }\n\n        return matchingTriggers;\n    }\n\n\n    /**\n     * <p>\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     *\n     * @return The desired <code>Trigger</code>, or null if there is no\n     *         match.\n     */\n    public OperableTrigger retrieveTrigger(TriggerKey triggerKey) {\n        synchronized(lock) {\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n    \n            return (tw != null) ? (OperableTrigger)tw.getTrigger().clone() : null;\n        }\n    }\n    \n    /**\n     * Determine whether a {@link Job} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param jobKey the identifier to check for\n     * @return true if a Job exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    public boolean checkExists(JobKey jobKey) throws JobPersistenceException {\n        synchronized(lock) {\n            JobWrapper jw = jobsByKey.get(jobKey);\n            return (jw != null);\n        }\n    }\n    \n    /**\n     * Determine whether a {@link Trigger} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param triggerKey the identifier to check for\n     * @return true if a Trigger exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    public boolean checkExists(TriggerKey triggerKey) throws JobPersistenceException {\n        synchronized(lock) {\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n    \n            return (tw != null);\n        }\n    }\n \n    /**\n     * <p>\n     * Get the current state of the identified <code>{@link Trigger}</code>.\n     * </p>\n     *\n     * @see TriggerState#NORMAL\n     * @see TriggerState#PAUSED\n     * @see TriggerState#COMPLETE\n     * @see TriggerState#ERROR\n     * @see TriggerState#BLOCKED\n     * @see TriggerState#NONE\n     */\n    public TriggerState getTriggerState(TriggerKey triggerKey) throws JobPersistenceException {\n        synchronized(lock) {\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n            \n            if (tw == null) {\n                return TriggerState.NONE;\n            }\n    \n            if (tw.state == TriggerWrapper.STATE_COMPLETE) {\n                return TriggerState.COMPLETE;\n            }\n    \n            if (tw.state == TriggerWrapper.STATE_PAUSED) {\n                return TriggerState.PAUSED;\n            }\n    \n            if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) {\n                return TriggerState.PAUSED;\n            }\n    \n            if (tw.state == TriggerWrapper.STATE_BLOCKED) {\n                return TriggerState.BLOCKED;\n            }\n    \n            if (tw.state == TriggerWrapper.STATE_ERROR) {\n                return TriggerState.ERROR;\n            }\n    \n            return TriggerState.NORMAL;\n        }\n    }\n\n    /**\n     * Reset the current state of the identified <code>{@link Trigger}</code>\n     * from {@link TriggerState#ERROR} to {@link TriggerState#NORMAL} or\n     * {@link TriggerState#PAUSED} as appropriate.\n     *\n     * <p>Only affects triggers that are in ERROR state - if identified trigger is not\n     * in that state then the result is a no-op.</p>\n     *\n     * <p>The result will be the trigger returning to the normal, waiting to\n     * be fired state, unless the trigger's group has been paused, in which\n     * case it will go into the PAUSED state.</p>\n     */\n    public void resetTriggerFromErrorState(final TriggerKey triggerKey) throws JobPersistenceException {\n\n        synchronized (lock) {\n\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n            // does the trigger exist?\n            if (tw == null) {\n                return;\n            }\n            // is the trigger in error state?\n            if (tw.state != TriggerWrapper.STATE_ERROR) {\n                return;\n            }\n\n            if(pausedTriggerGroups.contains(triggerKey.getGroup())) {\n                tw.state = TriggerWrapper.STATE_PAUSED;\n            }\n            else {\n                tw.state = TriggerWrapper.STATE_WAITING;\n                timeTriggers.add(tw);\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Store the given <code>{@link org.quartz.Calendar}</code>.\n     * </p>\n     *\n     * @param calendar\n     *          The <code>Calendar</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Calendar</code> existing\n     *          in the <code>JobStore</code> with the same name and group\n     *          should be over-written.\n     * @param updateTriggers\n     *          If <code>true</code>, any <code>Trigger</code>s existing\n     *          in the <code>JobStore</code> that reference an existing\n     *          Calendar with the same name with have their next fire time\n     *          re-computed with the new <code>Calendar</code>.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Calendar</code> with the same name already\n     *           exists, and replaceExisting is set to false.\n     */\n    public void storeCalendar(String name,\n            Calendar calendar, boolean replaceExisting, boolean updateTriggers)\n        throws ObjectAlreadyExistsException {\n\n        calendar = (Calendar) calendar.clone();\n        \n        synchronized (lock) {\n    \n            Object obj = calendarsByName.get(name);\n    \n            if (obj != null && !replaceExisting) {\n                throw new ObjectAlreadyExistsException(\n                    \"Calendar with name '\" + name + \"' already exists.\");\n            } else if (obj != null) {\n                calendarsByName.remove(name);\n            }\n    \n            calendarsByName.put(name, calendar);\n    \n            if(obj != null && updateTriggers) {\n                for (TriggerWrapper tw : getTriggerWrappersForCalendar(name)) {\n                    OperableTrigger trig = tw.getTrigger();\n                    boolean removed = timeTriggers.remove(tw);\n\n                    trig.updateWithNewCalendar(calendar, getMisfireThreshold());\n\n                    if (removed) {\n                        timeTriggers.add(tw);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Remove (delete) the <code>{@link org.quartz.Calendar}</code> with the\n     * given name.\n     * </p>\n     *\n     * <p>\n     * If removal of the <code>Calendar</code> would result in\n     * <code>Trigger</code>s pointing to nonexistent calendars, then a\n     * <code>JobPersistenceException</code> will be thrown.</p>\n     *       *\n     * @param calName The name of the <code>Calendar</code> to be removed.\n     * @return <code>true</code> if a <code>Calendar</code> with the given name\n     * was found and removed from the store.\n     */\n    public boolean removeCalendar(String calName)\n        throws JobPersistenceException {\n        int numRefs = 0;\n\n        synchronized (lock) {\n            for (TriggerWrapper wrapper : triggersByKey.values()) {\n                OperableTrigger trigger = wrapper.trigger;\n                if (trigger.getCalendarName() != null\n                        && trigger.getCalendarName().equals(calName)) {\n                    numRefs++;\n                }\n            }\n        }\n\n        if (numRefs > 0) {\n            throw new JobPersistenceException(\n                    \"Calender cannot be removed if it referenced by a Trigger!\");\n        }\n\n        return (calendarsByName.remove(calName) != null);\n    }\n\n    /**\n     * <p>\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     * </p>\n     *\n     * @param calName\n     *          The name of the <code>Calendar</code> to be retrieved.\n     * @return The desired <code>Calendar</code>, or null if there is no\n     *         match.\n     */\n    public Calendar retrieveCalendar(String calName) {\n        synchronized (lock) {\n            Calendar cal = calendarsByName.get(calName);\n            if(cal != null)\n                return (Calendar) cal.clone();\n            return null;\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.JobDetail}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     * </p>\n     */\n    public int getNumberOfJobs() {\n        synchronized (lock) {\n            return jobsByKey.size();\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.Trigger}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     * </p>\n     */\n    public int getNumberOfTriggers() {\n        synchronized (lock) {\n            return triggersByKey.size();\n        }\n    }\n\n    /**\n     * <p>\n     * Get the number of <code>{@link org.quartz.Calendar}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     * </p>\n     */\n    public int getNumberOfCalendars() {\n        synchronized (lock) {\n            return calendarsByName.size();\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Job}</code> s that\n     * match the given groupMatcher.\n     * </p>\n     */\n    public Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) {\n        Set<JobKey> outList = null;\n        synchronized (lock) {\n\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            String compareToValue = matcher.getCompareToValue();\n\n            switch(operator) {\n                case EQUALS:\n                    HashMap<JobKey, JobWrapper> grpMap = jobsByGroup.get(compareToValue);\n                    if (grpMap != null) {\n                        outList = new HashSet<>();\n\n                        for (JobWrapper jw : grpMap.values()) {\n\n                            if (jw != null) {\n                                outList.add(jw.jobDetail.getKey());\n                            }\n                        }\n                    }\n                    break;\n\n                default:\n                    for (Map.Entry<String, HashMap<JobKey, JobWrapper>> entry : jobsByGroup.entrySet()) {\n                        if(operator.evaluate(entry.getKey(), compareToValue) && entry.getValue() != null) {\n                            if(outList == null) {\n                                outList = new HashSet<>();\n                            }\n                            for (JobWrapper jobWrapper : entry.getValue().values()) {\n                                if(jobWrapper != null) {\n                                    outList.add(jobWrapper.jobDetail.getKey());\n                                }\n                            }\n                        }\n                    }\n            }\n        }\n\n        return outList == null ? java.util.Collections.emptySet() : outList;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Calendar}</code> s\n     * in the <code>JobStore</code>.\n     * </p>\n     *\n     * <p>\n     * If there are no Calendars in the given group name, the result should be\n     * a zero-length array (not <code>null</code>).\n     * </p>\n     */\n    public List<String> getCalendarNames() {\n        synchronized(lock) {\n            return new LinkedList<>(calendarsByName.keySet());\n        }\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code> s\n     * that match the given groupMatcher.\n     * </p>\n     */\n    public Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) {\n        Set<TriggerKey> outList = null;\n        synchronized (lock) {\n\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            String compareToValue = matcher.getCompareToValue();\n\n            switch(operator) {\n                case EQUALS:\n                    HashMap<TriggerKey, TriggerWrapper> grpMap = triggersByGroup.get(compareToValue);\n                    if (grpMap != null) {\n                        outList = new HashSet<>();\n\n                        for (TriggerWrapper tw : grpMap.values()) {\n\n                            if (tw != null) {\n                                outList.add(tw.trigger.getKey());\n                            }\n                        }\n                    }\n                    break;\n\n                default:\n                    for (Map.Entry<String, HashMap<TriggerKey, TriggerWrapper>> entry : triggersByGroup.entrySet()) {\n                        if(operator.evaluate(entry.getKey(), compareToValue) && entry.getValue() != null) {\n                            if(outList == null) {\n                                outList = new HashSet<>();\n                            }\n                            for (TriggerWrapper triggerWrapper : entry.getValue().values()) {\n                                if(triggerWrapper != null) {\n                                    outList.add(triggerWrapper.trigger.getKey());\n                                }\n                            }\n                        }\n                    }\n            }\n        }\n\n        return outList == null ? Collections.emptySet() : outList;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Job}</code>\n     * groups.\n     * </p>\n     */\n    public List<String> getJobGroupNames() {\n        List<String> outList;\n\n        synchronized (lock) {\n            outList = new LinkedList<>(jobsByGroup.keySet());\n        }\n\n        return outList;\n    }\n\n    /**\n     * <p>\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code>\n     * groups.\n     * </p>\n     */\n    public List<String> getTriggerGroupNames() {\n        LinkedList<String> outList;\n\n        synchronized (lock) {\n            outList = new LinkedList<>(triggersByGroup.keySet());\n        }\n\n        return outList;\n    }\n\n    /**\n     * <p>\n     * Get all of the Triggers that are associated to the given Job.\n     * </p>\n     *\n     * <p>\n     * If there are no matches, a zero-length array should be returned.\n     * </p>\n     */\n    public List<OperableTrigger> getTriggersForJob(JobKey jobKey) {\n        ArrayList<OperableTrigger> trigList = new ArrayList<>();\n\n        synchronized (lock) {\n            List<TriggerWrapper> jobList = triggersByJob.get(jobKey);\n            if(jobList != null) {\n                for(TriggerWrapper tw : jobList) {\n                    trigList.add((OperableTrigger) tw.trigger.clone());\n                }\n            }\n        }\n\n        return trigList;\n    }\n\n    protected ArrayList<TriggerWrapper> getTriggerWrappersForJob(JobKey jobKey) {\n        ArrayList<TriggerWrapper> trigList = new ArrayList<>();\n\n        synchronized (lock) {\n            List<TriggerWrapper> jobList = triggersByJob.get(jobKey);\n            if(jobList != null) {\n                trigList.addAll(jobList);\n            }\n        }\n\n        return trigList;\n    }\n\n    protected ArrayList<TriggerWrapper> getTriggerWrappersForCalendar(String calName) {\n        ArrayList<TriggerWrapper> trigList = new ArrayList<>();\n\n        synchronized (lock) {\n            for (TriggerWrapper tw : triggersByKey.values()) {\n                String tcalName = tw.getTrigger().getCalendarName();\n                if (tcalName != null && tcalName.equals(calName)) {\n                    trigList.add(tw);\n                }\n            }\n        }\n\n        return trigList;\n    }\n\n    /**\n     * <p>\n     * Pause the <code>{@link Trigger}</code> with the given name.\n     * </p>\n     *\n     */\n    public void pauseTrigger(TriggerKey triggerKey) {\n\n        synchronized (lock) {\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n    \n            // does the trigger exist?\n            if (tw == null) {\n                return;\n            }\n    \n            // if the trigger is \"complete\" pausing it does not make sense...\n            if (tw.state == TriggerWrapper.STATE_COMPLETE) {\n                return;\n            }\n\n            if(tw.state == TriggerWrapper.STATE_BLOCKED) {\n                tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;\n            } else {\n                tw.state = TriggerWrapper.STATE_PAUSED;\n            }\n\n            timeTriggers.remove(tw);\n        }\n    }\n\n    /**\n     * <p>\n     * Pause all of the known <code>{@link Trigger}s</code> matching.\n     * </p>\n     *\n     * <p>\n     * The JobStore should \"remember\" the groups paused, and impose the\n     * pause on any new triggers that are added to one of these groups while the group is\n     * paused.\n     * </p>\n     *\n     */\n    public List<String> pauseTriggers(GroupMatcher<TriggerKey> matcher) {\n\n        List<String> pausedGroups;\n        synchronized (lock) {\n            pausedGroups = new LinkedList<>();\n\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            switch (operator) {\n                case EQUALS:\n                    if(pausedTriggerGroups.add(matcher.getCompareToValue())) {\n                        pausedGroups.add(matcher.getCompareToValue());\n                    }\n                    break;\n                default :\n                    for (String group : triggersByGroup.keySet()) {\n                        if(operator.evaluate(group, matcher.getCompareToValue())) {\n                            if(pausedTriggerGroups.add(matcher.getCompareToValue())) {\n                                pausedGroups.add(group);\n                            }\n                        }\n                    }\n            }\n\n            for (String pausedGroup : pausedGroups) {\n                Set<TriggerKey> keys = getTriggerKeys(GroupMatcher.triggerGroupEquals(pausedGroup));\n\n                for (TriggerKey key: keys) {\n                    pauseTrigger(key);\n                }\n            }\n        }\n\n        return pausedGroups;\n    }\n\n    /**\n     * <p>\n     * Pause the <code>{@link org.quartz.JobDetail}</code> with the given\n     * name - by pausing all of its current <code>Trigger</code>s.\n     * </p>\n     *\n     */\n    public void pauseJob(JobKey jobKey) {\n        synchronized (lock) {\n            List<OperableTrigger> triggersOfJob = getTriggersForJob(jobKey);\n            for (OperableTrigger trigger: triggersOfJob) {\n                pauseTrigger(trigger.getKey());\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the\n     * given group - by pausing all of their <code>Trigger</code>s.\n     * </p>\n     *\n     *\n     * <p>\n     * The JobStore should \"remember\" that the group is paused, and impose the\n     * pause on any new jobs that are added to the group while the group is\n     * paused.\n     * </p>\n     */\n    public List<String> pauseJobs(GroupMatcher<JobKey> matcher) {\n        List<String> pausedGroups = new LinkedList<>();\n        synchronized (lock) {\n\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            switch (operator) {\n                case EQUALS:\n                    if (pausedJobGroups.add(matcher.getCompareToValue())) {\n                        pausedGroups.add(matcher.getCompareToValue());\n                    }\n                    break;\n                default :\n                    for (String group : jobsByGroup.keySet()) {\n                        if(operator.evaluate(group, matcher.getCompareToValue())) {\n                            if (pausedJobGroups.add(group)) {\n                                pausedGroups.add(group);\n                            }\n                        }\n                    }\n            }\n\n            for (String groupName : pausedGroups) {\n                for (JobKey jobKey: getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {\n                    List<OperableTrigger> triggersOfJob = getTriggersForJob(jobKey);\n                    for (OperableTrigger trigger: triggersOfJob) {\n                        pauseTrigger(trigger.getKey());\n                    }\n                }\n            }\n        }\n\n        return pausedGroups;\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link Trigger}</code> with the given\n     * key.\n     * </p>\n     *\n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     */\n    public void resumeTrigger(TriggerKey triggerKey) {\n\n        synchronized (lock) {\n            TriggerWrapper tw = triggersByKey.get(triggerKey);\n    \n            // does the trigger exist?\n            if (tw == null) {\n                return;\n            }\n    \n            OperableTrigger trig = tw.getTrigger();\n    \n            // if the trigger is not paused resuming it does not make sense...\n            if (tw.state != TriggerWrapper.STATE_PAUSED &&\n                    tw.state != TriggerWrapper.STATE_PAUSED_BLOCKED) {\n                return;\n            }\n\n            if(blockedJobs.contains( trig.getJobKey() )) {\n                tw.state = TriggerWrapper.STATE_BLOCKED;\n            } else {\n                tw.state = TriggerWrapper.STATE_WAITING;\n            }\n\n            applyMisfire(tw);\n\n            if (tw.state == TriggerWrapper.STATE_WAITING) {\n                timeTriggers.add(tw);\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the\n     * given group.\n     * </p>\n     *\n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     */\n    public List<String> resumeTriggers(GroupMatcher<TriggerKey> matcher) {\n        Set<String> groups = new HashSet<>();\n\n        synchronized (lock) {\n            Set<TriggerKey> keys = getTriggerKeys(matcher);\n\n            for (TriggerKey triggerKey: keys) {\n                groups.add(triggerKey.getGroup());\n                if(triggersByKey.get(triggerKey) != null) {\n                    String jobGroup = triggersByKey.get(triggerKey).jobKey.getGroup();\n                    if(pausedJobGroups.contains(jobGroup)) {\n                        continue;\n                    }\n                }\n                resumeTrigger(triggerKey);\n            }\n\n            // Find all matching paused trigger groups, and then remove them.\n            StringMatcher.StringOperatorName operator = matcher.getCompareWithOperator();\n            LinkedList<String> pausedGroups = new LinkedList<>();\n            String matcherGroup = matcher.getCompareToValue();\n            switch (operator) {\n                case EQUALS:\n                    if(pausedTriggerGroups.contains(matcherGroup)) {\n                        pausedGroups.add(matcher.getCompareToValue());\n                    }\n                    break;\n                default :\n                    for (String group : pausedTriggerGroups) {\n                        if(operator.evaluate(group, matcherGroup)) {\n                            pausedGroups.add(group);\n                        }\n                    }\n            }\n            for (String pausedGroup : pausedGroups) {\n                pausedTriggerGroups.remove(pausedGroup);\n            }\n        }\n\n        return new ArrayList<>(groups);\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with\n     * the given name.\n     * </p>\n     *\n     * <p>\n     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one\n     * or more fire-times, then the <code>Trigger</code>'s misfire\n     * instruction will be applied.\n     * </p>\n     *\n     */\n    public void resumeJob(JobKey jobKey) {\n\n        synchronized (lock) {\n            List<OperableTrigger> triggersOfJob = getTriggersForJob(jobKey);\n            for (OperableTrigger trigger: triggersOfJob) {\n                resumeTrigger(trigger.getKey());\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>\n     * in the given group.\n     * </p>\n     *\n     * <p>\n     * If any of the <code>Job</code> s had <code>Trigger</code> s that\n     * missed one or more fire-times, then the <code>Trigger</code>'s\n     * misfire instruction will be applied.\n     * </p>\n     *\n     */\n    public Collection<String> resumeJobs(GroupMatcher<JobKey> matcher) {\n        Set<String> resumedGroups = new HashSet<>();\n        synchronized (lock) {\n            Set<JobKey> keys = getJobKeys(matcher);\n\n            for (String pausedJobGroup : pausedJobGroups) {\n                if(matcher.getCompareWithOperator().evaluate(pausedJobGroup, matcher.getCompareToValue())) {\n                    resumedGroups.add(pausedJobGroup);\n                }\n            }\n\n            for (String resumedGroup : resumedGroups) {\n                pausedJobGroups.remove(resumedGroup);\n            }\n\n            for (JobKey key: keys) {\n                List<OperableTrigger> triggersOfJob = getTriggersForJob(key);\n                for (OperableTrigger trigger: triggersOfJob) {\n                    resumeTrigger(trigger.getKey());\n                }\n            }\n        }\n        return resumedGroups;\n    }\n\n    /**\n     * <p>\n     * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     *\n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     *\n     * @see #resumeAll()\n     * @see #pauseTrigger(org.quartz.TriggerKey)\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    public void pauseAll() {\n\n        synchronized (lock) {\n            List<String> names = getTriggerGroupNames();\n\n            for (String name: names) {\n                pauseTriggers(GroupMatcher.triggerGroupEquals(name));\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>\n     * on every group.\n     * </p>\n     *\n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     * @see #pauseAll()\n     */\n    public void resumeAll() {\n\n        synchronized (lock) {\n            pausedJobGroups.clear();\n            resumeTriggers(GroupMatcher.anyTriggerGroup());\n        }\n    }\n\n    protected boolean applyMisfire(TriggerWrapper tw) {\n\n        long misfireTime = System.currentTimeMillis();\n        if (getMisfireThreshold() > 0) {\n            misfireTime -= getMisfireThreshold();\n        }\n\n        Date tnft = tw.trigger.getNextFireTime();\n        if (tnft == null || tnft.getTime() > misfireTime \n                || tw.trigger.getMisfireInstruction() == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { \n            return false; \n        }\n\n        Calendar cal = null;\n        if (tw.trigger.getCalendarName() != null) {\n            cal = retrieveCalendar(tw.trigger.getCalendarName());\n        }\n\n        signaler.notifyTriggerListenersMisfired((OperableTrigger)tw.trigger.clone());\n\n        tw.trigger.updateAfterMisfire(cal);\n\n        if (tw.trigger.getNextFireTime() == null) {\n            tw.state = TriggerWrapper.STATE_COMPLETE;\n            signaler.notifySchedulerListenersFinalized(tw.trigger);\n            synchronized (lock) {\n                timeTriggers.remove(tw);\n            }\n        } else return !tnft.equals(tw.trigger.getNextFireTime());\n\n        return true;\n    }\n\n    private static final AtomicLong ftrCtr = new AtomicLong(System.currentTimeMillis());\n\n    protected String getFiredTriggerRecordId() {\n        return String.valueOf(ftrCtr.incrementAndGet());\n    }\n\n    /**\n     * <p>\n     * Get a handle to the next trigger to be fired, and mark it as 'reserved'\n     * by the calling scheduler.\n     * </p>\n     *\n     * @see #releaseAcquiredTrigger(OperableTrigger)\n     */\n    public List<OperableTrigger> acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) {\n        synchronized (lock) {\n            List<OperableTrigger> result = new ArrayList<>();\n            Set<JobKey> acquiredJobKeysForNoConcurrentExec = new HashSet<>();\n            Set<TriggerWrapper> excludedTriggers = new HashSet<>();\n            long batchEnd = noLaterThan;\n            \n            // return empty list if store has no triggers.\n            if (timeTriggers.isEmpty())\n                return result;\n            \n            while (true) {\n                TriggerWrapper tw;\n\n                try {\n                    tw = timeTriggers.first();\n                    if (tw == null)\n                        break;\n                    timeTriggers.remove(tw);\n                } catch (java.util.NoSuchElementException nsee) {\n                    break;\n                }\n\n                if (tw.trigger.getNextFireTime() == null) {\n                    continue;\n                }\n\n                if (applyMisfire(tw)) {\n                    if (tw.trigger.getNextFireTime() != null) {\n                        timeTriggers.add(tw);\n                    }\n                    continue;\n                }\n\n                if (tw.getTrigger().getNextFireTime().getTime() > batchEnd) {\n                    timeTriggers.add(tw);\n                    break;\n                }\n                \n                // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then\n                // put it back into the timeTriggers set and continue to search for next trigger.\n                JobKey jobKey = tw.trigger.getJobKey();\n                JobDetail job = jobsByKey.get(tw.trigger.getJobKey()).jobDetail;\n                if (job.isConcurrentExecutionDisallowed()) {\n                    if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) {\n                        excludedTriggers.add(tw);\n                        continue; // go to next trigger in store.\n                    } else {\n                        acquiredJobKeysForNoConcurrentExec.add(jobKey);\n                    }\n                }\n\n                tw.state = TriggerWrapper.STATE_ACQUIRED;\n                tw.trigger.setFireInstanceId(getFiredTriggerRecordId());\n                OperableTrigger trig = (OperableTrigger) tw.trigger.clone();\n                if (result.isEmpty()) {\n                    batchEnd = Math.max(tw.trigger.getNextFireTime().getTime(), System.currentTimeMillis()) + timeWindow;\n                }\n                result.add(trig);\n                if (result.size() == maxCount)\n                    break;\n            }\n\n            // If we did excluded triggers to prevent ACQUIRE state due to DisallowConcurrentExecution, we need to add them back to store.\n            if (!excludedTriggers.isEmpty())\n                timeTriggers.addAll(excludedTriggers);\n            return result;\n        }\n    }\n\n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler no longer plans to\n     * fire the given <code>Trigger</code>, that it had previously acquired\n     * (reserved).\n     * </p>\n     */\n    public void releaseAcquiredTrigger(OperableTrigger trigger) {\n        synchronized (lock) {\n            TriggerWrapper tw = triggersByKey.get(trigger.getKey());\n            if (tw != null && tw.state == TriggerWrapper.STATE_ACQUIRED) {\n                tw.state = TriggerWrapper.STATE_WAITING;\n                timeTriggers.add(tw);\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler is now firing the\n     * given <code>Trigger</code> (executing its associated <code>Job</code>),\n     * that it had previously acquired (reserved).\n     * </p>\n     */\n    public List<TriggerFiredResult> triggersFired(List<OperableTrigger> firedTriggers) {\n\n        synchronized (lock) {\n            List<TriggerFiredResult> results = new ArrayList<>();\n\n            for (OperableTrigger trigger : firedTriggers) {\n                TriggerWrapper tw = triggersByKey.get(trigger.getKey());\n                // was the trigger deleted since being acquired?\n                if (tw == null) {\n                    continue;\n                }\n                // was the trigger completed, paused, blocked, etc. since being acquired?\n                if (tw.state != TriggerWrapper.STATE_ACQUIRED) {\n                    continue;\n                }\n\n                Calendar cal = null;\n                if (tw.trigger.getCalendarName() != null) {\n                    cal = retrieveCalendar(tw.trigger.getCalendarName());\n                    if(cal == null)\n                        continue;\n                }\n                Date prevFireTime = trigger.getPreviousFireTime();\n                // in case trigger was replaced between acquiring and firing\n                timeTriggers.remove(tw);\n                // call triggered on our copy, and the scheduler's copy\n                tw.trigger.triggered(cal);\n                trigger.triggered(cal);\n                //tw.state = TriggerWrapper.STATE_EXECUTING;\n                tw.state = TriggerWrapper.STATE_WAITING;\n\n                TriggerFiredBundle bundle = new TriggerFiredBundle(retrieveJob(\n                        tw.jobKey), trigger, cal,\n                        false, new Date(), trigger.getPreviousFireTime(), prevFireTime,\n                        trigger.getNextFireTime());\n\n                JobDetail job = bundle.getJobDetail();\n\n                if (job.isConcurrentExecutionDisallowed()) {\n                    ArrayList<TriggerWrapper> trigs = getTriggerWrappersForJob(job.getKey());\n                    for (TriggerWrapper ttw : trigs) {\n                        if (ttw.state == TriggerWrapper.STATE_WAITING) {\n                            ttw.state = TriggerWrapper.STATE_BLOCKED;\n                        }\n                        if (ttw.state == TriggerWrapper.STATE_PAUSED) {\n                            ttw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;\n                        }\n                        timeTriggers.remove(ttw);\n                    }\n                    blockedJobs.add(job.getKey());\n                } else if (tw.trigger.getNextFireTime() != null) {\n                    synchronized (lock) {\n                        timeTriggers.add(tw);\n                    }\n                }\n\n                results.add(new TriggerFiredResult(bundle));\n            }\n            return results;\n        }\n    }\n\n    /**\n     * <p>\n     * Inform the <code>JobStore</code> that the scheduler has completed the\n     * firing of the given <code>Trigger</code> (and the execution its\n     * associated <code>Job</code>), and that the <code>{@link org.quartz.JobDataMap}</code>\n     * in the given <code>JobDetail</code> should be updated if the <code>Job</code>\n     * is stateful.\n     * </p>\n     */\n    public void triggeredJobComplete(OperableTrigger trigger,\n            JobDetail jobDetail, CompletedExecutionInstruction triggerInstCode) {\n\n        synchronized (lock) {\n\n            JobWrapper jw = jobsByKey.get(jobDetail.getKey());\n            TriggerWrapper tw = triggersByKey.get(trigger.getKey());\n\n            // It's possible that the job is null if:\n            //   1- it was deleted during execution\n            //   2- RAMJobStore is being used only for volatile jobs / triggers\n            //      from the JDBC job store\n            if (jw != null) {\n                JobDetail jd = jw.jobDetail;\n\n                if (jd.isPersistJobDataAfterExecution()) {\n                    JobDataMap newData = jobDetail.getJobDataMap();\n                    if (newData != null) {\n                        newData = (JobDataMap)newData.clone();\n                        newData.clearDirtyFlag();\n                    }\n                    jd = jd.getJobBuilder().setJobData(newData).build();\n                    jw.jobDetail = jd;\n                }\n                if (jd.isConcurrentExecutionDisallowed()) {\n                    blockedJobs.remove(jd.getKey());\n                    ArrayList<TriggerWrapper> trigs = getTriggerWrappersForJob(jd.getKey());\n                    for(TriggerWrapper ttw : trigs) {\n                        if (ttw.state == TriggerWrapper.STATE_BLOCKED) {\n                            ttw.state = TriggerWrapper.STATE_WAITING;\n                            timeTriggers.add(ttw);\n                        }\n                        if (ttw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) {\n                            ttw.state = TriggerWrapper.STATE_PAUSED;\n                        }\n                    }\n                    signaler.signalSchedulingChange(0L);\n                }\n            } else { // even if it was deleted, there may be cleanup to do\n                blockedJobs.remove(jobDetail.getKey());\n            }\n    \n            // check for trigger deleted during execution...\n            if (tw != null) {\n                if (triggerInstCode == CompletedExecutionInstruction.DELETE_TRIGGER) {\n                    \n                    if(trigger.getNextFireTime() == null) {\n                        // double check for possible reschedule within job \n                        // execution, which would cancel the need to delete...\n                        if(tw.getTrigger().getNextFireTime() == null) {\n                            removeTrigger(trigger.getKey());\n                        }\n                    } else {\n                        removeTrigger(trigger.getKey());\n                        signaler.signalSchedulingChange(0L);\n                    }\n                } else if (triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) {\n                    tw.state = TriggerWrapper.STATE_COMPLETE;\n                    timeTriggers.remove(tw);\n                    signaler.signalSchedulingChange(0L);\n                } else if(triggerInstCode == CompletedExecutionInstruction.SET_TRIGGER_ERROR) {\n                    getLog().info(\"Trigger {} set to ERROR state.\", trigger.getKey());\n                    tw.state = TriggerWrapper.STATE_ERROR;\n                    signaler.signalSchedulingChange(0L);\n                } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR) {\n                    getLog().info(\"All triggers of Job {} set to ERROR state.\", trigger.getJobKey());\n                    setAllTriggersOfJobToState(trigger.getJobKey(), TriggerWrapper.STATE_ERROR);\n                    signaler.signalSchedulingChange(0L);\n                } else if (triggerInstCode == CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) {\n                    setAllTriggersOfJobToState(trigger.getJobKey(), TriggerWrapper.STATE_COMPLETE);\n                    signaler.signalSchedulingChange(0L);\n                }\n            }\n        }\n    }\n\n    @Override\n    public long getAcquireRetryDelay(int failureCount) {\n        return 20;\n    }\n\n    protected void setAllTriggersOfJobToState(JobKey jobKey, int state) {\n        ArrayList<TriggerWrapper> tws = getTriggerWrappersForJob(jobKey);\n        for (TriggerWrapper tw : tws) {\n            tw.state = state;\n            if (state != TriggerWrapper.STATE_WAITING) {\n                timeTriggers.remove(tw);\n            }\n        }\n    }\n    \n    @SuppressWarnings(\"UnusedDeclaration\")\n    protected String peekTriggers() {\n\n        StringBuilder str = new StringBuilder();\n        synchronized (lock) {\n            for (TriggerWrapper triggerWrapper : triggersByKey.values()) {\n                str.append(triggerWrapper.trigger.getKey().getName());\n                str.append(\"/\");\n            }\n        }\n        str.append(\" | \");\n\n        synchronized (lock) {\n            for (TriggerWrapper timeTrigger : timeTriggers) {\n                str.append(timeTrigger.trigger.getKey().getName());\n                str.append(\"->\");\n            }\n        }\n\n        return str.toString();\n    }\n\n    /** \n     * @see org.quartz.spi.JobStore#getPausedTriggerGroups()\n     */\n    public Set<String> getPausedTriggerGroups() throws JobPersistenceException {\n\n        return new HashSet<>(pausedTriggerGroups);\n    }\n\n    public void setInstanceId(String schedInstId) {\n        //\n    }\n\n    public void setInstanceName(String schedName) {\n        //\n    }\n\n    public void setThreadPoolSize(final int poolSize) {\n        //\n    }\n\n    public long getEstimatedTimeToReleaseAndAcquireTrigger() {\n        return 5;\n    }\n\n    public boolean isClustered() {\n        return false;\n    }\n\n}\n\n/*******************************************************************************\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * \n * Helper Classes. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n */\n\nclass TriggerWrapperComparator implements Comparator<TriggerWrapper>, java.io.Serializable {\n  \n    private static final long serialVersionUID = 8809557142191514261L;\n\n    final TriggerTimeComparator ttc = new TriggerTimeComparator();\n    \n    public int compare(TriggerWrapper trig1, TriggerWrapper trig2) {\n        return ttc.compare(trig1.trigger, trig2.trigger);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return (obj instanceof TriggerWrapperComparator);\n    }\n\n    @Override\n    public int hashCode() {\n        return super.hashCode();\n    }\n}\n\nclass JobWrapper {\n\n    public final JobKey key;\n\n    public JobDetail jobDetail;\n\n    JobWrapper(JobDetail jobDetail) {\n        this.jobDetail = jobDetail;\n        key = jobDetail.getKey();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj instanceof JobWrapper) {\n            JobWrapper jw = (JobWrapper) obj;\n            return jw.key.equals(this.key);\n        }\n\n        return false;\n    }\n    \n    @Override\n    public int hashCode() {\n        return key.hashCode(); \n    }\n}\n\nclass TriggerWrapper {\n\n    public final TriggerKey key;\n\n    public final JobKey jobKey;\n\n    public final OperableTrigger trigger;\n\n    public int state = STATE_WAITING;\n\n    public static final int STATE_WAITING = 0;\n\n    public static final int STATE_ACQUIRED = 1;\n\n    @SuppressWarnings(\"UnusedDeclaration\")\n    public static final int STATE_EXECUTING = 2;\n\n    public static final int STATE_COMPLETE = 3;\n\n    public static final int STATE_PAUSED = 4;\n\n    public static final int STATE_BLOCKED = 5;\n\n    public static final int STATE_PAUSED_BLOCKED = 6;\n\n    public static final int STATE_ERROR = 7;\n    \n    TriggerWrapper(OperableTrigger trigger) {\n        if(trigger == null)\n            throw new IllegalArgumentException(\"Trigger cannot be null!\");\n        this.trigger = trigger;\n        key = trigger.getKey();\n        this.jobKey = trigger.getJobKey();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj instanceof TriggerWrapper) {\n            TriggerWrapper tw = (TriggerWrapper) obj;\n            return tw.key.equals(this.key);\n        }\n\n        return false;\n    }\n\n    @Override\n    public int hashCode() {\n        return key.hashCode(); \n    }\n\n    \n    public OperableTrigger getTrigger() {\n        return this.trigger;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SimpleClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.quartz.spi.ClassLoadHelper;\n\nimport java.lang.reflect.AccessibleObject;\nimport java.lang.reflect.Method;\nimport java.net.URL;\nimport java.io.InputStream;\n\n/**\n * A <code>ClassLoadHelper</code> that simply calls <code>Class.forName(..)</code>.\n * \n * @see org.quartz.spi.ClassLoadHelper\n * @see org.quartz.simpl.ThreadContextClassLoadHelper\n * @see org.quartz.simpl.CascadingClassLoadHelper\n * @see org.quartz.simpl.LoadingLoaderClassLoadHelper\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic class SimpleClassLoadHelper implements ClassLoadHelper {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    public void initialize() {\n    }\n\n    /**\n     * Return the class with the given name.\n     */\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        return Class.forName(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Class<? extends T> loadClass(String name, Class<T> clazz)\n            throws ClassNotFoundException {\n        return (Class<? extends T>) loadClass(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    public URL getResource(String name) {\n        return getClassLoader().getResource(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    public InputStream getResourceAsStream(String name) {\n        return getClassLoader().getResourceAsStream(name);\n    }\n\n    /**\n     * Enable sharing of the class-loader with 3rd party.\n     *\n     * @return the class-loader user be the helper.\n     */\n    public ClassLoader getClassLoader() {\n        // To follow the same behavior of Class.forName(...) I had to play\n        // dirty (Supported by Sun, IBM & BEA JVMs)\n        try {\n            // Get a reference to this class' class-loader\n            ClassLoader cl = this.getClass().getClassLoader();\n            // Create a method instance representing the protected\n            // getCallerClassLoader method of class ClassLoader\n            Method mthd = ClassLoader.class.getDeclaredMethod(\n                    \"getCallerClassLoader\", new Class<?>[0]);\n            // Make the method accessible.\n            AccessibleObject.setAccessible(new AccessibleObject[] {mthd}, true);\n            // Try to get the caller's class-loader\n            return (ClassLoader)mthd.invoke(cl, new Object[0]);\n        } catch (Throwable all) {\n            // Use this class' class-loader\n            return this.getClass().getClassLoader();\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SimpleInstanceIdGenerator.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.simpl;\n\nimport java.net.InetAddress;\n\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.InstanceIdGenerator;\n\n/**\n * The default InstanceIdGenerator used by Quartz when instance id is to be\n * automatically generated.  Instance id is of the form HOSTNAME + CURRENT_TIME.\n * \n * @see InstanceIdGenerator\n * @see HostnameInstanceIdGenerator\n */\npublic class SimpleInstanceIdGenerator implements InstanceIdGenerator {\n    public String generateInstanceId() throws SchedulerException {\n        try {\n            return InetAddress.getLocalHost().getHostName() + System.currentTimeMillis();\n        } catch (Exception e) {\n            throw new SchedulerException(\"Couldn't get host name!\", e);\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SimpleJobFactory.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.simpl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.JobFactory;\nimport org.quartz.spi.TriggerFiredBundle;\n\n/**\n * The default JobFactory used by Quartz - simply calls \n * <code>newInstance()</code> on the job class.\n * \n * @see JobFactory\n * @see PropertySettingJobFactory\n * \n * @author jhouse\n */\npublic class SimpleJobFactory implements JobFactory {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    protected Logger getLog() {\n        return log;\n    }\n    \n    public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {\n\n        JobDetail jobDetail = bundle.getJobDetail();\n        Class<? extends Job> jobClass = jobDetail.getJobClass();\n        try {\n            if(log.isDebugEnabled()) {\n                log.debug(\"Producing instance of Job '{}', class={}\", jobDetail.getKey(), jobClass.getName());\n            }\n\n            return jobClass.getDeclaredConstructor().newInstance();\n        } catch (Exception e) {\n            throw new SchedulerException(\n                    \"Problem instantiating class '\"\n                            + jobDetail.getJobClass().getName() + \"'\", e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SimpleThreadPool.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.spi.ThreadPool;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * <p>\n * This is class is a simple implementation of a thread pool, based on the\n * <code>{@link org.quartz.spi.ThreadPool}</code> interface.\n * </p>\n * \n * <p>\n * <CODE>Runnable</CODE> objects are sent to the pool with the <code>{@link #runInThread(Runnable)}</code>\n * method, which blocks until a <code>Thread</code> becomes available.\n * </p>\n * \n * <p>\n * The pool has a fixed number of <code>Thread</code>s, and does not grow or\n * shrink based on demand.\n * </p>\n * \n * @author James House\n * @author Juergen Donnerstag\n */\npublic class SimpleThreadPool implements ThreadPool {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private int count = -1;\n\n    private int prio = Thread.NORM_PRIORITY;\n\n    private boolean isShutdown = false;\n    private boolean handoffPending = false;\n\n    private boolean inheritLoader = false;\n\n    private boolean inheritGroup = true;\n\n    private boolean makeThreadsDaemons = false;\n\n    private ThreadGroup threadGroup;\n\n    private final Object nextRunnableLock = new Object();\n\n    private List<WorkerThread> workers;\n    private final LinkedList<WorkerThread> availWorkers = new LinkedList<>();\n    private final LinkedList<WorkerThread> busyWorkers = new LinkedList<>();\n\n    private String threadNamePrefix;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n    \n    private String schedulerInstanceName;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a new (unconfigured) <code>SimpleThreadPool</code>.\n     * </p>\n     * \n     * @see #setThreadCount(int)\n     * @see #setThreadPriority(int)\n     */\n    public SimpleThreadPool() {\n    }\n\n    /**\n     * <p>\n     * Create a new <code>SimpleThreadPool</code> with the specified number\n     * of <code>Thread</code> s that have the given priority.\n     * </p>\n     * \n     * @param threadCount\n     *          the number of worker <code>Threads</code> in the pool, must\n     *          be &gt; 0.\n     * @param threadPriority\n     *          the thread priority for the worker threads.\n     * \n     * @see java.lang.Thread\n     */\n    public SimpleThreadPool(int threadCount, int threadPriority) {\n        setThreadCount(threadCount);\n        setThreadPriority(threadPriority);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public Logger getLog() {\n        return log;\n    }\n\n    public int getPoolSize() {\n        return getThreadCount();\n    }\n\n    /**\n     * <p>\n     * Set the number of worker threads in the pool - has no effect after\n     * <code>initialize()</code> has been called.\n     * </p>\n     */\n    public void setThreadCount(int count) {\n        this.count = count;\n    }\n\n    /**\n     * <p>\n     * Get the number of worker threads in the pool.\n     * </p>\n     */\n    public int getThreadCount() {\n        return count;\n    }\n\n    /**\n     * <p>\n     * Set the thread priority of worker threads in the pool - has no effect\n     * after <code>initialize()</code> has been called.\n     * </p>\n     */\n    public void setThreadPriority(int prio) {\n        this.prio = prio;\n    }\n\n    /**\n     * <p>\n     * Get the thread priority of worker threads in the pool.\n     * </p>\n     */\n    public int getThreadPriority() {\n        return prio;\n    }\n\n    public void setThreadNamePrefix(String prefix) {\n        this.threadNamePrefix = prefix;\n    }\n\n    public String getThreadNamePrefix() {\n        return threadNamePrefix;\n    }\n\n    /**\n     * @return Returns the\n     *         threadsInheritContextClassLoaderOfInitializingThread.\n     */\n    public boolean isThreadsInheritContextClassLoaderOfInitializingThread() {\n        return inheritLoader;\n    }\n\n    /**\n     * @param inheritLoader\n     *          The threadsInheritContextClassLoaderOfInitializingThread to\n     *          set.\n     */\n    public void setThreadsInheritContextClassLoaderOfInitializingThread(\n            boolean inheritLoader) {\n        this.inheritLoader = inheritLoader;\n    }\n\n    public boolean isThreadsInheritGroupOfInitializingThread() {\n        return inheritGroup;\n    }\n\n    public void setThreadsInheritGroupOfInitializingThread(\n            boolean inheritGroup) {\n        this.inheritGroup = inheritGroup;\n    }\n\n\n    /**\n     * @return Returns the value of makeThreadsDaemons.\n     */\n    public boolean isMakeThreadsDaemons() {\n        return makeThreadsDaemons;\n    }\n\n    /**\n     * @param makeThreadsDaemons\n     *          The value of makeThreadsDaemons to set.\n     */\n    public void setMakeThreadsDaemons(boolean makeThreadsDaemons) {\n        this.makeThreadsDaemons = makeThreadsDaemons;\n    }\n    \n    public void setInstanceId(String schedInstId) {\n    }\n\n    public void setInstanceName(String schedName) {\n        schedulerInstanceName = schedName;\n    }\n\n    public void initialize() throws SchedulerConfigException {\n\n        if(workers != null && !workers.isEmpty()) // already initialized...\n            return;\n        \n        if (count <= 0) {\n            throw new SchedulerConfigException(\n                    \"Thread count must be > 0\");\n        }\n        if (prio <= 0 || prio > 9) {\n            throw new SchedulerConfigException(\n                    \"Thread priority must be > 0 and <= 9\");\n        }\n\n        if(isThreadsInheritGroupOfInitializingThread()) {\n            threadGroup = Thread.currentThread().getThreadGroup();\n        } else {\n            // follow the threadGroup tree to the root thread group.\n            threadGroup = Thread.currentThread().getThreadGroup();\n            ThreadGroup parent = threadGroup;\n            while ( !parent.getName().equals(\"main\") ) {\n                threadGroup = parent;\n                parent = threadGroup.getParent();\n            }\n            threadGroup = new ThreadGroup(parent, schedulerInstanceName + \"-SimpleThreadPool\");\n            if (isMakeThreadsDaemons()) {\n                threadGroup.setDaemon(true);\n            }\n        }\n\n\n        if (isThreadsInheritContextClassLoaderOfInitializingThread()) {\n            getLog().info(\"Job execution threads will use class loader of thread: {}\", Thread.currentThread().getName());\n        }\n\n        // create the worker threads and start them\n        for (WorkerThread wt : createWorkerThreads(count)) {\n            wt.start();\n            availWorkers.add(wt);\n        }\n    }\n\n    protected List<WorkerThread> createWorkerThreads(int createCount) {\n        workers = new LinkedList<>();\n        for (int i = 1; i<= createCount; ++i) {\n            String threadPrefix = getThreadNamePrefix();\n            if (threadPrefix == null) {\n                threadPrefix = schedulerInstanceName + \"_Worker\";\n            }\n            WorkerThread wt = new WorkerThread(this, threadGroup,\n                threadPrefix + \"-\" + i,\n                getThreadPriority(),\n                isMakeThreadsDaemons());\n            if (isThreadsInheritContextClassLoaderOfInitializingThread()) {\n                wt.setContextClassLoader(Thread.currentThread()\n                        .getContextClassLoader());\n            }\n            workers.add(wt);\n        }\n\n        return workers;\n    }\n\n    /**\n     * <p>\n     * Terminate any worker threads in this thread group.\n     * </p>\n     * \n     * <p>\n     * Jobs currently in progress will complete.\n     * </p>\n     */\n    public void shutdown() {\n        shutdown(true);\n    }\n\n    /**\n     * <p>\n     * Terminate any worker threads in this thread group.\n     * </p>\n     * \n     * <p>\n     * Jobs currently in progress will complete.\n     * </p>\n     */\n    public void shutdown(boolean waitForJobsToComplete) {\n\n        synchronized (nextRunnableLock) {\n            getLog().debug(\"Shutting down threadpool...\");\n\n            isShutdown = true;\n\n            if(workers == null) // case where the pool wasn't even initialize()ed\n                return;\n\n            // signal each worker thread to shut down\n            for (WorkerThread wt : workers) {\n                wt.shutdown();\n                availWorkers.remove(wt);\n            }\n\n            // Give waiting (wait(1000)) worker threads a chance to shut down.\n            // Active worker threads will shut down after finishing their\n            // current job.\n            nextRunnableLock.notifyAll();\n\n            if (waitForJobsToComplete) {\n\n                boolean interrupted = false;\n                try {\n                    // wait for hand-off in runInThread to complete...\n                    while(handoffPending) {\n                        try {\n                            nextRunnableLock.wait(100);\n                        } catch(InterruptedException e) {\n                            interrupted = true;\n                        }\n                    }\n\n                    // Wait until all worker threads are shut down\n                    while (!busyWorkers.isEmpty()) {\n                        WorkerThread wt = (WorkerThread) busyWorkers.getFirst();\n                        try {\n                            getLog().debug(\"Waiting for thread {} to shut down\", wt.getName());\n\n                            // note: with waiting infinite time the\n                            // application may appear to 'hang'.\n                            nextRunnableLock.wait(2000);\n                        } catch (InterruptedException e) {\n                            interrupted = true;\n                        }\n                    }\n\n                    Iterator<WorkerThread> workerThreads = workers.iterator();\n                    while(workerThreads.hasNext()) {\n                        WorkerThread wt = (WorkerThread) workerThreads.next();\n                        try {\n                            wt.join();\n                            workerThreads.remove();\n                        } catch (InterruptedException e) {\n                            interrupted = true;\n                        }\n                    }\n                } finally {\n                    if (interrupted) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n\n                getLog().debug(\"No executing jobs remaining, all threads stopped.\");\n            }\n            getLog().debug(\"Shutdown of threadpool complete.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Run the given <code>Runnable</code> object in the next available\n     * <code>Thread</code>. If while waiting the thread pool is asked to\n     * shut down, the Runnable is executed immediately within a new additional\n     * thread.\n     * </p>\n     * \n     * @param runnable\n     *          the <code>Runnable</code> to be added.\n     */\n    public boolean runInThread(Runnable runnable) {\n        if (runnable == null) {\n            return false;\n        }\n\n        synchronized (nextRunnableLock) {\n\n            handoffPending = true;\n\n            // Wait until a worker thread is available\n            while ((availWorkers.isEmpty()) && !isShutdown) {\n                try {\n                    nextRunnableLock.wait(500);\n                } catch (InterruptedException ignore) {\n                }\n            }\n\n            if (!isShutdown) {\n                WorkerThread wt = (WorkerThread)availWorkers.removeFirst();\n                busyWorkers.add(wt);\n                wt.run(runnable);\n            } else {\n                // If the thread pool is going down, execute the Runnable\n                // within a new additional worker thread (no thread from the pool).\n                WorkerThread wt = new WorkerThread(this, threadGroup,\n                        \"WorkerThread-LastJob\", prio, isMakeThreadsDaemons(), runnable);\n                busyWorkers.add(wt);\n                workers.add(wt);\n                wt.start();\n            }\n            nextRunnableLock.notifyAll();\n            handoffPending = false;\n        }\n\n        return true;\n    }\n\n    public int blockForAvailableThreads() {\n        synchronized(nextRunnableLock) {\n\n            while((availWorkers.isEmpty() || handoffPending) && !isShutdown) {\n                try {\n                    nextRunnableLock.wait(500);\n                } catch (InterruptedException ignore) {\n                }\n            }\n\n            return availWorkers.size();\n        }\n    }\n\n    protected void makeAvailable(WorkerThread wt) {\n        synchronized(nextRunnableLock) {\n            if(!isShutdown) {\n                availWorkers.add(wt);\n            }\n            busyWorkers.remove(wt);\n            nextRunnableLock.notifyAll();\n        }\n    }\n\n    protected void clearFromBusyWorkersList(WorkerThread wt) {\n        synchronized(nextRunnableLock) {\n            busyWorkers.remove(wt);\n            nextRunnableLock.notifyAll();\n        }\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * WorkerThread Class.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * A Worker loops, waiting to execute tasks.\n     * </p>\n     */\n    class WorkerThread extends Thread {\n\n        private final Object lock = new Object();\n\n        // A flag that signals the WorkerThread to terminate.\n        private final AtomicBoolean run = new AtomicBoolean(true);\n\n        private final SimpleThreadPool tp;\n\n        private Runnable runnable;\n        \n        private boolean runOnce = false;\n\n        /**\n         * <p>\n         * Create a worker thread and start it. Waiting for the next Runnable,\n         * executing it, and waiting for the next Runnable, until the shutdown\n         * flag is set.\n         * </p>\n         */\n        WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name,\n                     int prio, boolean isDaemon) {\n\n            this(tp, threadGroup, name, prio, isDaemon, null);\n        }\n\n        /**\n         * <p>\n         * Create a worker thread, start it, execute the runnable and terminate\n         * the thread (one time execution).\n         * </p>\n         */\n        WorkerThread(SimpleThreadPool tp, ThreadGroup threadGroup, String name,\n                     int prio, boolean isDaemon, Runnable runnable) {\n\n            super(threadGroup, name);\n            this.tp = tp;\n            this.runnable = runnable;\n            if(runnable != null)\n                runOnce = true;\n            setPriority(prio);\n            setDaemon(isDaemon);\n        }\n\n        /**\n         * <p>\n         * Signal the thread that it should terminate.\n         * </p>\n         */\n        void shutdown() {\n            run.set(false);\n        }\n\n        public void run(Runnable newRunnable) {\n            synchronized(lock) {\n                if(runnable != null) {\n                    throw new IllegalStateException(\"Already running a Runnable!\");\n                }\n\n                runnable = newRunnable;\n                lock.notifyAll();\n            }\n        }\n\n        /**\n         * <p>\n         * Loop, executing targets as they are received.\n         * </p>\n         */\n        @Override\n        public void run() {\n            boolean ran = false;\n            \n            while (run.get()) {\n                try {\n                    synchronized(lock) {\n                        while (runnable == null && run.get()) {\n                            lock.wait(500);\n                        }\n\n                        if (runnable != null) {\n                            ran = true;\n                            runnable.run();\n                        }\n                    }\n                } catch (InterruptedException unblock) {\n                    // do nothing (loop will terminate if shutdown() was called\n                    try {\n                        getLog().error(\"Worker thread was interrupt()'ed.\", unblock);\n                    } catch(Exception e) {\n                        // ignore to help with a tomcat glitch\n                    }\n                } catch (Throwable exceptionInRunnable) {\n                    try {\n                        getLog().error(\"Error while executing the Runnable: \",\n                            exceptionInRunnable);\n                    } catch(Exception e) {\n                        // ignore to help with a tomcat glitch\n                    }\n                } finally {\n                    synchronized(lock) {\n                        runnable = null;\n                    }\n                    // repair the thread in case the runnable mucked it up...\n                    if(getPriority() != tp.getThreadPriority()) {\n                        setPriority(tp.getThreadPriority());\n                    }\n\n                    if (runOnce) {\n                           run.set(false);\n                        clearFromBusyWorkersList(this);\n                    } else if(ran) {\n                        ran = false;\n                        makeAvailable(this);\n                    }\n\n                }\n            }\n\n            //if (log.isDebugEnabled())\n            try {\n                getLog().debug(\"WorkerThread is shut down.\");\n            } catch(Exception e) {\n                // ignore to help with a tomcat glitch\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SimpleTimeBroker.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport java.util.Date;\n\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.spi.TimeBroker;\n\n/**\n * <p>\n * The interface to be implemented by classes that want to provide a mechanism\n * by which the <code>{@link org.quartz.core.QuartzScheduler}</code> can\n * reliably determine the current time.\n * </p>\n * \n * <p>\n * In general, the default implementation of this interface (<code>{@link org.quartz.simpl.SimpleTimeBroker}</code>-\n * which simply uses <code>System.getCurrentTimeMillis()</code> )is\n * sufficient. However situations may exist where this default scheme is\n * lacking in its robustness - especially when Quartz is used in a clustered\n * configuration. For example, if one or more of the machines in the cluster\n * has a system time that varies by more than a few seconds from the clocks on\n * the other systems in the cluster, scheduling confusion will result.\n * </p>\n * \n * @see org.quartz.core.QuartzScheduler\n * \n * @author James House\n */\n@SuppressWarnings(\"deprecation\")\npublic class SimpleTimeBroker implements TimeBroker {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the current time, simply using <code>new Date()</code>.\n     * </p>\n     */\n    public Date getCurrentTime() {\n        return new Date();\n    }\n\n    public void initialize() throws SchedulerConfigException {\n        // do nothing...\n    }\n\n    public void shutdown() {\n        // do nothing...\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/SystemPropertyInstanceIdGenerator.java",
    "content": "package org.quartz.simpl;\n\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.InstanceIdGenerator;\n\n/**\n * InstanceIdGenerator that will use a {@link SystemPropertyInstanceIdGenerator#SYSTEM_PROPERTY system property}\n * to configure the scheduler.  The default system property name to use the value of {@link #SYSTEM_PROPERTY}, but\n * can be specified via the \"systemPropertyName\" property.\n * \n * You can also set the properties \"postpend\" and \"prepend\" to String values that will be added to the beginning\n * or end (respectively) of the value found in the system property.\n * \n * If no value set for the property, a {@link org.quartz.SchedulerException} is thrown\n *\n * @author Alex Snaps\n */\npublic class SystemPropertyInstanceIdGenerator implements InstanceIdGenerator {\n\n  /**\n   * System property to read the instanceId from\n   */\n  public static final String SYSTEM_PROPERTY = \"org.quartz.scheduler.instanceId\";\n\n  private String prepend = null;\n  private String postpend = null;\n  private String systemPropertyName = SYSTEM_PROPERTY;\n  \n  /**\n   * Returns the cluster wide value for this scheduler instance's id, based on a system property\n   * @return the value of the system property named by the value of {@link #getSystemPropertyName()} - which defaults\n   * to {@link #SYSTEM_PROPERTY}.\n   * @throws SchedulerException Shouldn't a value be found\n   */\n  public String generateInstanceId() throws SchedulerException {\n    String property = System.getProperty(getSystemPropertyName());\n    if(property == null) {\n      throw new SchedulerException(\"No value for '\" + SYSTEM_PROPERTY\n                                   + \"' system property found, please configure your environment accordingly!\");\n    }\n    if(getPrepend() != null)\n        property = getPrepend() + property;\n    if(getPostpend() != null)\n        property = property + getPostpend();\n    \n    return property;\n  }\n  \n  /**\n   * A String of text to prepend (add to the beginning) to the instanceId \n   * found in the system property.\n   */\n  public String getPrepend() {\n    return prepend;\n  }\n\n  /**\n   * A String of text to prepend (add to the beginning) to the instanceId \n   * found in the system property.\n   * \n   * @param prepend the value to prepend, or null if none is desired.\n   */\n  public void setPrepend(String prepend) {\n    this.prepend = prepend == null ?  null  : prepend.trim();\n  }\n    \n  /**\n   * A String of text to postpend (add to the end) to the instanceId \n   * found in the system property.\n   */\n  public String getPostpend() {\n    return postpend;\n  }\n\n  /**\n   * A String of text to postpend (add to the end) to the instanceId \n   * found in the system property.\n   * \n   * @param postpend the value to postpend, or null if none is desired.\n   */\n  public void setPostpend(String postpend) {\n    this.postpend = postpend == null ?  null : postpend.trim();\n  }\n\n  /**\n   * The name of the system property from which to obtain the instanceId.\n   * \n   * Defaults to {@link #SYSTEM_PROPERTY}.\n   * \n   */  \n  public String getSystemPropertyName() {\n    return systemPropertyName;\n  }\n\n  /**\n   * The name of the system property from which to obtain the instanceId.\n   * \n   * Defaults to {@link #SYSTEM_PROPERTY}.\n   * \n   * @param systemPropertyName the system property name\n   */\n  public void setSystemPropertyName(String systemPropertyName) {\n    this.systemPropertyName = systemPropertyName == null ? SYSTEM_PROPERTY : systemPropertyName.trim();\n  }\n  \n} \n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/ThreadContextClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.quartz.spi.ClassLoadHelper;\n\nimport java.net.URL;\nimport java.io.InputStream;\n\n/**\n * A <code>ClassLoadHelper</code> that uses either the current thread's\n * context class loader (<code>Thread.currentThread().getContextClassLoader().loadClass( .. )</code>).\n * \n * @see org.quartz.spi.ClassLoadHelper\n * @see org.quartz.simpl.InitThreadContextClassLoadHelper\n * @see org.quartz.simpl.SimpleClassLoadHelper\n * @see org.quartz.simpl.CascadingClassLoadHelper\n * @see org.quartz.simpl.LoadingLoaderClassLoadHelper\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic class ThreadContextClassLoadHelper implements ClassLoadHelper {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    public void initialize() {\n    }\n\n    /**\n     * Return the class with the given name.\n     */\n    public Class<?> loadClass(String name) throws ClassNotFoundException {\n        return getClassLoader().loadClass(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Class<? extends T> loadClass(String name, Class<T> clazz)\n            throws ClassNotFoundException {\n        return (Class<? extends T>) loadClass(name);\n    }\n    \n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    public URL getResource(String name) {\n        return getClassLoader().getResource(name);\n    }\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    public InputStream getResourceAsStream(String name) {\n        return getClassLoader().getResourceAsStream(name);\n    }\n\n    /**\n     * Enable sharing of the class-loader with 3rd party.\n     *\n     * @return the class-loader user be the helper.\n     */\n    public ClassLoader getClassLoader() {\n        return Thread.currentThread().getContextClassLoader();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/ZeroSizeThreadPool.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.simpl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.spi.ThreadPool;\n\n/**\n * <p>\n * This is class is a simple implementation of a zero size thread pool, based on the\n * <code>{@link org.quartz.spi.ThreadPool}</code> interface.\n * </p>\n * \n * <p>\n * The pool has zero <code>Thread</code>s and does not grow or shrink based on demand.\n * Which means it is obviously not useful for most scenarios.  When it may be useful\n * is to prevent creating any worker threads at all - which may be desirable for\n * the sole purpose of preserving system resources in the case where the scheduler\n * instance only exists in order to schedule jobs, but which will never execute\n * jobs (e.g. will never have start() called on it).\n * </p>\n * \n * @author Wayne Fay\n */\npublic class ZeroSizeThreadPool implements ThreadPool {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a new <code>ZeroSizeThreadPool</code>.\n     * </p>\n     */\n    public ZeroSizeThreadPool() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public Logger getLog() {\n        return log;\n    }\n\n    public int getPoolSize() {\n        return 0;\n    }\n\n    public void initialize() throws SchedulerConfigException {\n    }\n\n    public void shutdown() {\n        shutdown(true);\n    }\n\n    public void shutdown(boolean waitForJobsToComplete) {\n        getLog().debug(\"shutdown complete\");\n    }\n\n    public boolean runInThread(Runnable runnable) {\n        throw new UnsupportedOperationException(\"This ThreadPool should not be used on Scheduler instances that are start()ed.\");\n    }\n\n    public int blockForAvailableThreads() {\n        throw new UnsupportedOperationException(\"This ThreadPool should not be used on Scheduler instances that are start()ed.\");\n    }\n\n    public void setInstanceId(String schedInstId) {\n    }\n\n    public void setInstanceName(String schedName) {\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/simpl/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.simpl</title>\n</head>\n<body>\n<p>Contains simple / light-weight implementations (with no dependencies on\nexternal libraries) of interfaces required by the\norg.quartz.core.QuartzScheduler.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project\n  for more information.\n\n</body>\n</html>\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/ClassLoadHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport java.net.URL;\nimport java.io.InputStream;\n\n/**\n * An interface for classes wishing to provide the service of loading classes\n * and resources within the scheduler...\n * \n * @author jhouse\n * @author pl47ypus\n */\npublic interface ClassLoadHelper {\n\n    /**\n     * Called to give the ClassLoadHelper a chance to initialize itself,\n     * including the opportunity to \"steal\" the class loader off of the calling\n     * thread, which is the thread that is initializing Quartz.\n     */\n    void initialize();\n\n    /**\n     * Return the class with the given name.\n     *\n     * @param name the FQCN of the class to load.\n     * @return the requested class.\n     * @throws ClassNotFoundException if the class can be found in the classpath.\n     */\n    Class<?> loadClass(String name) throws ClassNotFoundException;\n\n    /**\n     * Return the class of the given type with the given name.\n     *\n     * @param name the FQCN of the class to load.\n     * @return the requested class.\n     * @throws ClassNotFoundException if the class can be found in the classpath.\n     */\n    <T> Class<? extends T> loadClass(String name, Class<T> clazz) throws ClassNotFoundException;\n    \n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     *\n     * @param name name of the desired resource\n     * @return a java.net.URL object\n     */\n    URL getResource(String name);\n\n    /**\n     * Finds a resource with a given name. This method returns null if no\n     * resource with this name is found.\n     *\n     * @param name name of the desired resource\n     * @return a java.io.InputStream object\n     */\n    InputStream getResourceAsStream(String name);\n\n    /**\n     * Enable sharing of the class-loader with 3rd party (e.g. digester).\n     *\n     * @return the class-loader user be the helper.\n     */\n    ClassLoader getClassLoader();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/InstanceIdGenerator.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.spi;\n\nimport org.quartz.SchedulerException;\n\n/**\n * <p>\n * An InstanceIdGenerator is responsible for generating the clusterwide unique \n * instance id for a <code>Scheduler</code> node.\n * </p>\n * \n * <p>\n * This interface may be of use to those wishing to have specific control over \n * the mechanism by which the <code>Scheduler</code> instances in their \n * application are named.\n * </p>\n * \n * @see org.quartz.simpl.SimpleInstanceIdGenerator\n */\npublic interface InstanceIdGenerator {\n    /**\n     * Generate the instance id for a <code>Scheduler</code>\n     * \n     * @return The clusterwide unique instance id.\n     */\n    String generateInstanceId() throws SchedulerException;\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/JobFactory.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.spi;\n\nimport org.quartz.Job;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\n/**\n * <p>\n * A JobFactory is responsible for producing instances of <code>Job</code>\n * classes.\n * </p>\n * \n * <p>\n * This interface may be of use to those wishing to have their application\n * produce <code>Job</code> instances via some special mechanism, such as to\n * give the opportunity for dependency injection.\n * </p>\n * \n * @see org.quartz.Scheduler#setJobFactory(JobFactory)\n * @see org.quartz.simpl.SimpleJobFactory\n * @see org.quartz.simpl.PropertySettingJobFactory\n * \n * @author James House\n */\npublic interface JobFactory {\n\n    /**\n     * Called by the scheduler at the time of the trigger firing, in order to\n     * produce a <code>Job</code> instance on which to call execute.\n     * \n     * <p>\n     * It should be extremely rare for this method to throw an exception -\n     * basically only the case where there is no way at all to instantiate\n     * and prepare the Job for execution.  When the exception is thrown, the\n     * Scheduler will move all triggers associated with the Job into the\n     * <code>Trigger.STATE_ERROR</code> state, which will require human\n     * intervention (e.g. an application restart after fixing whatever \n     * configuration problem led to the issue with instantiating the Job. \n     * </p>\n     * \n     * @param bundle\n     *            The TriggerFiredBundle from which the <code>JobDetail</code>\n     *            and other info relating to the trigger firing can be obtained.\n     * @param scheduler a handle to the scheduler that is about to execute the job.\n     * @throws SchedulerException if there is a problem instantiating the Job.\n     * @return the newly instantiated Job\n     */\n    Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException;\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/JobStore.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.spi;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.quartz.Calendar;\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.ObjectAlreadyExistsException;\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.Trigger.CompletedExecutionInstruction;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.impl.matchers.GroupMatcher;\n\n/**\n * <p>\n * The interface to be implemented by classes that want to provide a <code>{@link org.quartz.Job}</code>\n * and <code>{@link org.quartz.Trigger}</code> storage mechanism for the\n * <code>{@link org.quartz.core.QuartzScheduler}</code>'s use.\n * </p>\n *\n * <p>\n * Storage of <code>Job</code> s and <code>Trigger</code> s should be keyed\n * on the combination of their name and group for uniqueness.\n * </p>\n *\n * @see org.quartz.core.QuartzScheduler\n * @see org.quartz.Trigger\n * @see org.quartz.Job\n * @see org.quartz.JobDetail\n * @see org.quartz.JobDataMap\n * @see org.quartz.Calendar\n *\n * @author James House\n * @author Eric Mueller\n */\npublic interface JobStore {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Called by the QuartzScheduler before the <code>JobStore</code> is\n     * used, in order to give the it a chance to initialize.\n     */\n    void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) \n        throws SchedulerConfigException;\n\n    /**\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * the scheduler has started.\n     */\n    void schedulerStarted() throws SchedulerException ;\n\n    /**\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * the scheduler has been paused.\n     */\n    void schedulerPaused();\n\n    /**\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * the scheduler has resumed after being paused.\n     */\n    void schedulerResumed();\n\n    /**\n     * Called by the QuartzScheduler to inform the <code>JobStore</code> that\n     * it should free up all of it's resources because the scheduler is\n     * shutting down.\n     */\n    void shutdown();\n\n    boolean supportsPersistence();\n    \n    /**\n     * How long (in milliseconds) the <code>JobStore</code> implementation \n     * estimates that it will take to release a trigger and acquire a new one. \n     */\n    long getEstimatedTimeToReleaseAndAcquireTrigger();\n    \n    /**\n     * Whether or not the <code>JobStore</code> implementation is clustered.\n     */\n    boolean isClustered();\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Job & Trigger Storage methods\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.\n     *\n     * @param newJob\n     *          The <code>JobDetail</code> to be stored.\n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists.\n     */\n    void storeJobAndTrigger(JobDetail newJob, OperableTrigger newTrigger) \n        throws ObjectAlreadyExistsException, JobPersistenceException;\n\n    /**\n     * Store the given <code>{@link org.quartz.JobDetail}</code>.\n     *\n     * @param newJob\n     *          The <code>JobDetail</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Job</code> existing in the\n     *          <code>JobStore</code> with the same name and group should be\n     *          over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Job</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     */\n    void storeJob(JobDetail newJob, boolean replaceExisting) \n        throws ObjectAlreadyExistsException, JobPersistenceException;\n\n    void storeJobsAndTriggers(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace)\n        throws ObjectAlreadyExistsException, JobPersistenceException;\n\n    /**\n     * Remove (delete) the <code>{@link org.quartz.Job}</code> with the given\n     * key, and any <code>{@link org.quartz.Trigger}</code> s that reference\n     * it.\n     *\n     * <p>\n     * If removal of the <code>Job</code> results in an empty group, the\n     * group should be removed from the <code>JobStore</code>'s list of\n     * known group names.\n     * </p>\n     *\n     * @return <code>true</code> if a <code>Job</code> with the given name and\n     *         group was found and removed from the store.\n     */\n    boolean removeJob(JobKey jobKey) \n        throws JobPersistenceException;\n    \n    boolean removeJobs(List<JobKey> jobKeys)\n        throws JobPersistenceException;\n    \n    /**\n     * Retrieve the <code>{@link org.quartz.JobDetail}</code> for the given\n     * <code>{@link org.quartz.Job}</code>.\n     *\n     * @return The desired <code>Job</code>, or null if there is no match.\n     */\n    JobDetail retrieveJob(JobKey jobKey) \n        throws JobPersistenceException;\n\n    /**\n     * <p>\n     * Gets all the <code>{@link org.quartz.JobDetail}s</code> in the matching groups.\n     * </p>\n     * These will NOT necessarily be in lexicographical order, particularly on {@link org.quartz.simpl.RAMJobStore}\n     * You may need to re-sort them yourself.\n     * @param matcher Matcher to evaluate against known groups\n     * @return List of all JobDetail matching\n     * @throws JobPersistenceException On error\n     */\n    List<JobDetail> getJobDetails(GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException;\n\n\n    /**\n     * Store the given <code>{@link org.quartz.Trigger}</code>.\n     *\n     * @param newTrigger\n     *          The <code>Trigger</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Trigger</code> existing in\n     *          the <code>JobStore</code> with the same name and group should\n     *          be over-written.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Trigger</code> with the same name/group already\n     *           exists, and replaceExisting is set to false.\n     *\n     * @see #pauseTriggers(org.quartz.impl.matchers.GroupMatcher)\n     */\n    void storeTrigger(OperableTrigger newTrigger, boolean replaceExisting) \n        throws ObjectAlreadyExistsException, JobPersistenceException;\n\n    /**\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given key.\n     *\n     * <p>\n     * If removal of the <code>Trigger</code> results in an empty group, the\n     * group should be removed from the <code>JobStore</code>'s list of\n     * known group names.\n     * </p>\n     *\n     * <p>\n     * If removal of the <code>Trigger</code> results in an 'orphaned' <code>Job</code>\n     * that is not 'durable', then the <code>Job</code> should be deleted\n     * also.\n     * </p>\n     *\n     * @return <code>true</code> if a <code>Trigger</code> with the given\n     *         name and group was found and removed from the store.\n     */\n    boolean removeTrigger(TriggerKey triggerKey) throws JobPersistenceException;\n\n    boolean removeTriggers(List<TriggerKey> triggerKeys)\n        throws JobPersistenceException;\n\n    /**\n     * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the\n     * given key, and store the new given one - which must be associated\n     * with the same job.\n     * \n     * @param newTrigger\n     *          The new <code>Trigger</code> to be stored.\n     *\n     * @return <code>true</code> if a <code>Trigger</code> with the given\n     *         name and group was found and removed from the store.\n     */\n    boolean replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) \n        throws JobPersistenceException;\n\n    /**\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     *\n     * @return The desired <code>Trigger</code>, or null if there is no\n     *         match.\n     */\n    OperableTrigger retrieveTrigger(TriggerKey triggerKey) throws JobPersistenceException;\n\n    \n    /**\n     * Determine whether a {@link Job} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param jobKey the identifier to check for\n     * @return true if a Job exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    boolean checkExists(JobKey jobKey) throws JobPersistenceException; \n   \n    /**\n     * Determine whether a {@link Trigger} with the given identifier already \n     * exists within the scheduler.\n     * \n     * @param triggerKey the identifier to check for\n     * @return true if a Trigger exists with the given identifier\n     * @throws JobPersistenceException\n     */\n    boolean checkExists(TriggerKey triggerKey) throws JobPersistenceException;\n \n    /**\n     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s\n     * {@link Calendar}s.\n     * \n     * @throws JobPersistenceException\n     */\n    void clearAllSchedulingData() throws JobPersistenceException;\n    \n    /**\n     * Store the given <code>{@link org.quartz.Calendar}</code>.\n     *\n     * @param calendar\n     *          The <code>Calendar</code> to be stored.\n     * @param replaceExisting\n     *          If <code>true</code>, any <code>Calendar</code> existing\n     *          in the <code>JobStore</code> with the same name and group\n     *          should be over-written.\n     * @param updateTriggers\n     *          If <code>true</code>, any <code>Trigger</code>s existing\n     *          in the <code>JobStore</code> that reference an existing\n     *          Calendar with the same name with have their next fire time\n     *          re-computed with the new <code>Calendar</code>.\n     * @throws ObjectAlreadyExistsException\n     *           if a <code>Calendar</code> with the same name already\n     *           exists, and replaceExisting is set to false.\n     */\n    void storeCalendar(String name, Calendar calendar, boolean replaceExisting, boolean updateTriggers)\n        throws ObjectAlreadyExistsException, JobPersistenceException;\n\n    /**\n     * Remove (delete) the <code>{@link org.quartz.Calendar}</code> with the\n     * given name.\n     *\n     * <p>\n     * If removal of the <code>Calendar</code> would result in\n     * <code>Trigger</code>s pointing to nonexistent calendars, then a\n     * <code>JobPersistenceException</code> will be thrown.</p>\n     *       *\n     * @param calName The name of the <code>Calendar</code> to be removed.\n     * @return <code>true</code> if a <code>Calendar</code> with the given name\n     * was found and removed from the store.\n     */\n    boolean removeCalendar(String calName)\n        throws JobPersistenceException;\n\n    /**\n     * Retrieve the given <code>{@link org.quartz.Trigger}</code>.\n     *\n     * @param calName\n     *          The name of the <code>Calendar</code> to be retrieved.\n     * @return The desired <code>Calendar</code>, or null if there is no\n     *         match.\n     */\n    Calendar retrieveCalendar(String calName)\n        throws JobPersistenceException;\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Informational methods\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Get the number of <code>{@link org.quartz.Job}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     */\n    int getNumberOfJobs()\n        throws JobPersistenceException;\n\n    /**\n     * Get the number of <code>{@link org.quartz.Trigger}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     */\n    int getNumberOfTriggers()\n        throws JobPersistenceException;\n\n    /**\n     * Get the number of <code>{@link org.quartz.Calendar}</code> s that are\n     * stored in the <code>JobsStore</code>.\n     */\n    int getNumberOfCalendars()\n        throws JobPersistenceException;\n\n    /**\n     * Get the keys of all of the <code>{@link org.quartz.Job}</code> s that\n     * have the given group name.\n     *\n     * <p>\n     * If there are no jobs in the given group name, the result should be \n     * an empty collection (not <code>null</code>).\n     * </p>\n     */\n    Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException;\n\n    /**\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code> s\n     * that have the given group name.\n     *\n     * <p>\n     * If there are no triggers in the given group name, the result should be a\n     * zero-length array (not <code>null</code>).\n     * </p>\n     */\n    Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher)\n        throws JobPersistenceException;\n\n    /**\n     * Get the names of all of the <code>{@link org.quartz.Job}</code>\n     * groups.\n     *\n     * <p>\n     * If there are no known group names, the result should be a zero-length\n     * array (not <code>null</code>).\n     * </p>\n     */\n    List<String> getJobGroupNames()\n        throws JobPersistenceException;\n\n    /**\n     * Get the names of all of the <code>{@link org.quartz.Trigger}</code>\n     * groups.\n     *\n     * <p>\n     * If there are no known group names, the result should be a zero-length\n     * array (not <code>null</code>).\n     * </p>\n     */\n    List<String> getTriggerGroupNames()\n        throws JobPersistenceException;\n\n    /**\n     * Get the names of all of the <code>{@link org.quartz.Calendar}</code> s\n     * in the <code>JobStore</code>.\n     *\n     * <p>\n     * If there are no Calendars in the given group name, the result should be\n     * a zero-length array (not <code>null</code>).\n     * </p>\n     */\n    List<String> getCalendarNames()\n        throws JobPersistenceException;\n\n    /**\n     * Get all the Triggers that are associated to the given Job.\n     *\n     * <p>\n     * If there are no matches, a zero-length array should be returned.\n     * </p>\n     */\n    List<OperableTrigger> getTriggersForJob(JobKey jobKey) throws JobPersistenceException;\n\n    /**\n     * Get all the Triggers that are associated with the Job Group\n     *\n     * <p>\n     * If there are no matches, a zero-length array should be returned.\n     * </p>\n     * @param matcher A {@link GroupMatcher} to match job groups\n     * @return list of triggers - may be empty\n     * @throws JobPersistenceException thrown if there is an error\n     * @see #getTriggersByTriggerGroup(GroupMatcher)\n     * @see #getTriggersByJobAndTriggerGroup(GroupMatcher, GroupMatcher)\n     * */\n    default List<OperableTrigger> getTriggersByJobGroup(GroupMatcher<JobKey> matcher) throws JobPersistenceException {\n        return getTriggersByJobAndTriggerGroup(matcher, GroupMatcher.anyGroup());\n    }\n\n    /**\n     * Get all the Triggers that are associated with the Job Group\n     *\n     * <p>\n     * If there are no matches, a zero-length array should be returned.\n     * </p>\n     * @param matcher A {@link GroupMatcher} to match job groups\n     * @return list of triggers - may be empty\n     * @throws JobPersistenceException thrown if there is an error\n     * @see #getTriggersByJobGroup(GroupMatcher)\n     * @see #getTriggersByJobAndTriggerGroup(GroupMatcher, GroupMatcher)\n     * */\n    default List<OperableTrigger> getTriggersByTriggerGroup(GroupMatcher<TriggerKey> matcher) throws JobPersistenceException {\n        return getTriggersByJobAndTriggerGroup(GroupMatcher.anyGroup(), matcher);\n    }\n\n    /**\n     * Get all the Triggers that are associated with the Job &amp; trigger group matcher\n     * <br>\n     * note: requires the use of enhanced statements\n     * @param jobMatcher A {@link GroupMatcher} to match job groups\n     * @param triggerMatcher A {@link GroupMatcher} to match trigger groups\n     * @return list of triggers\n     * @throws JobPersistenceException thrown if there is an error saving the job\n     * @see #getTriggersByJobGroup(GroupMatcher)\n     * @see #getTriggersByTriggerGroup(GroupMatcher)\n     */\n    List<OperableTrigger> getTriggersByJobAndTriggerGroup(GroupMatcher<JobKey> jobMatcher, GroupMatcher<TriggerKey> triggerMatcher) throws JobPersistenceException;\n\n    /**\n     * Get the current state of the identified <code>{@link Trigger}</code>.\n     *\n     * @see Trigger.TriggerState\n     */\n    TriggerState getTriggerState(TriggerKey triggerKey) throws JobPersistenceException;\n\n    /**\n     * Reset the current state of the identified <code>{@link Trigger}</code>\n     * from {@link TriggerState#ERROR} to {@link TriggerState#NORMAL} or\n     * {@link TriggerState#PAUSED} as appropriate.\n     *\n     * <p>Only affects triggers that are in ERROR state - if identified trigger is not\n     * in that state then the result is a no-op.</p>\n     *\n     * <p>The result will be the trigger returning to the normal, waiting to\n     * be fired state, unless the trigger's group has been paused, in which\n     * case it will go into the PAUSED state.</p>\n     */\n    void resetTriggerFromErrorState(TriggerKey triggerKey) throws JobPersistenceException;\n\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Trigger State manipulation methods\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Pause the <code>{@link org.quartz.Trigger}</code> with the given key.\n     *\n     * @see #resumeTrigger(TriggerKey)\n     */\n    void pauseTrigger(TriggerKey triggerKey) throws JobPersistenceException;\n\n    /**\n     * Pause all of the <code>{@link org.quartz.Trigger}s</code> in the\n     * given group.\n     *\n     *\n     * <p>\n     * The JobStore should \"remember\" that the group is paused, and impose the\n     * pause on any new triggers that are added to the group while the group is\n     * paused.\n     * </p>\n     *\n     * @see #resumeTriggers(GroupMatcher)\n     */\n    Collection<String> pauseTriggers(GroupMatcher<TriggerKey> matcher) throws JobPersistenceException;\n\n    /**\n     * Pause the <code>{@link org.quartz.Job}</code> with the given name - by\n     * pausing all of its current <code>Trigger</code>s.\n     *\n     * @see #resumeJob(JobKey)\n     */\n    void pauseJob(JobKey jobKey) throws JobPersistenceException;\n\n    /**\n     * Pause all of the <code>{@link org.quartz.Job}s</code> in the given\n     * group - by pausing all of their <code>Trigger</code>s.\n     *\n     * <p>\n     * The JobStore should \"remember\" that the group is paused, and impose the\n     * pause on any new jobs that are added to the group while the group is\n     * paused.\n     * </p>\n     *\n     * @see #resumeJobs(GroupMatcher)\n     */\n    Collection<String> pauseJobs(GroupMatcher<JobKey> groupMatcher)\n        throws JobPersistenceException;\n\n    /**\n     * Resume (un-pause) the <code>{@link org.quartz.Trigger}</code> with the\n     * given key.\n     *\n     * <p>\n     * If the <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     * @see #pauseTrigger(TriggerKey)\n     */\n    void resumeTrigger(TriggerKey triggerKey) throws JobPersistenceException;\n\n    /**\n     * Resume (un-pause) all of the <code>{@link org.quartz.Trigger}s</code>\n     * in the given group.\n     *\n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     * @see #pauseTriggers(GroupMatcher)\n     */\n    Collection<String> resumeTriggers(GroupMatcher<TriggerKey> matcher)\n        throws JobPersistenceException;\n\n    /**\n     * Gets the set of all the paused trigger group names.\n     * @return a set of paused trigger group names.\n     * @throws JobPersistenceException thrown if there is an error\n     */\n    Set<String> getPausedTriggerGroups()\n        throws JobPersistenceException;\n\n    /**\n     * Resume (un-pause) the <code>{@link org.quartz.Job}</code> with the\n     * given key.\n     *\n     * <p>\n     * If any of the <code>Job</code>'s<code>Trigger</code> s missed one\n     * or more fire-times, then the <code>Trigger</code>'s misfire\n     * instruction will be applied.\n     * </p>\n     *\n     * @see #pauseJob(JobKey)\n     */\n    void resumeJob(JobKey jobKey) throws JobPersistenceException;\n\n    /**\n     * Resume (un-pause) all of the <code>{@link org.quartz.Job}s</code> in\n     * the given group.\n     *\n     * <p>\n     * If any of the <code>Job</code> s had <code>Trigger</code> s that\n     * missed one or more fire-times, then the <code>Trigger</code>'s\n     * misfire instruction will be applied.\n     * </p>\n     *\n     * @see #pauseJobs(GroupMatcher)\n     */\n    Collection<String> resumeJobs(GroupMatcher<JobKey> matcher)\n        throws JobPersistenceException;\n\n    /**\n     * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>\n     * on every group.\n     *\n     * <p>\n     * When <code>resumeAll()</code> is called (to un-pause), trigger misfire\n     * instructions WILL be applied.\n     * </p>\n     *\n     * @see #resumeAll()\n     * @see #pauseTriggers(GroupMatcher)\n     */\n    void pauseAll() throws JobPersistenceException;\n\n    /**\n     * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>\n     * on every group.\n     *\n     * <p>\n     * If any <code>Trigger</code> missed one or more fire-times, then the\n     * <code>Trigger</code>'s misfire instruction will be applied.\n     * </p>\n     *\n     * @see #pauseAll()\n     */\n    void resumeAll()\n        throws JobPersistenceException;\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Trigger-Firing methods\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Get a handle to the next trigger to be fired, and mark it as 'reserved'\n     * by the calling scheduler.\n     *\n     * @param noLaterThan If &gt; 0, the JobStore should only return a Trigger\n     * that will fire no later than the time represented in this value as\n     * milliseconds.\n     * @see #releaseAcquiredTrigger(OperableTrigger)\n     */\n    List<OperableTrigger> acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow)\n        throws JobPersistenceException;\n\n    /**\n     * Inform the <code>JobStore</code> that the scheduler no longer plans to\n     * fire the given <code>Trigger</code>, that it had previously acquired\n     * (reserved).\n     */\n    void releaseAcquiredTrigger(OperableTrigger trigger);\n\n    /**\n     * Inform the <code>JobStore</code> that the scheduler is now firing the\n     * given <code>Trigger</code> (executing its associated <code>Job</code>),\n     * that it had previously acquired (reserved).\n     *\n     * @return may return null if all the triggers or their calendars no longer exist, or\n     *         if the trigger was not successfully put into the 'executing'\n     *         state.  Preference is to return an empty list if none of the triggers\n     *         could be fired.\n     */\n    List<TriggerFiredResult> triggersFired(List<OperableTrigger> triggers) throws JobPersistenceException;\n\n    /**\n     * Inform the <code>JobStore</code> that the scheduler has completed the\n     * firing of the given <code>Trigger</code> (and the execution of its\n     * associated <code>Job</code> completed, threw an exception, or was vetoed),\n     * and that the <code>{@link org.quartz.JobDataMap}</code>\n     * in the given <code>JobDetail</code> should be updated if the <code>Job</code>\n     * is stateful.\n     */\n    void triggeredJobComplete(OperableTrigger trigger, JobDetail jobDetail, CompletedExecutionInstruction triggerInstCode);\n\n    /**\n     * Inform the <code>JobStore</code> of the Scheduler instance's Id,\n     * prior to initialize being invoked.\n     *\n     * @since 1.7\n     */\n    void setInstanceId(String schedInstId);\n\n    /**\n     * Inform the <code>JobStore</code> of the Scheduler instance's name,\n     * prior to initialize being invoked.\n     *\n     * @since 1.7\n     */\n    void setInstanceName(String schedName);\n\n    /**\n     * Tells the JobStore the pool size used to execute jobs\n     * @param poolSize amount of threads allocated for job execution\n     * @since 2.0\n     */\n    void setThreadPoolSize(int poolSize);\n\n    /**\n     * Get the amount of time (in ms) to wait when accessing this job store\n     * repeatedly fails.\n     *\n     * Called by the executor thread(s) when calls to\n     * {@link #acquireNextTriggers} fail more than once in succession, and the\n     * thread thus wants to wait a bit before trying again, to not consume\n     * 100% CPU, write huge amounts of errors into logs, etc. in cases like\n     * the DB being offline/restarting.\n     *\n     * The delay returned by implementations should be between 20 and\n     * 600000 milliseconds.\n     *\n     * @param failureCount the number of successive failures seen so far\n     * @return the time (in milliseconds) to wait before trying again\n     */\n    long getAcquireRetryDelay(int failureCount);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/MutableTrigger.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport java.util.Date;\n\nimport org.quartz.Calendar;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobKey;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\n\npublic interface MutableTrigger extends Trigger {\n\n    void setKey(TriggerKey key);\n\n    void setJobKey(JobKey key);\n\n    /**\n     * <p>\n     * Set a description for the <code>Trigger</code> instance - may be\n     * useful for remembering/displaying the purpose of the trigger, though the\n     * description has no meaning to Quartz.\n     * </p>\n     */\n    void setDescription(String description);\n\n    /**\n     * <p>\n     * Associate the <code>{@link Calendar}</code> with the given name with\n     * this Trigger.\n     * </p>\n     * \n     * @param calendarName\n     *          use <code>null</code> to dis-associate a Calendar.\n     */\n    void setCalendarName(String calendarName);\n\n    /**\n     * <p>\n     * Set the <code>JobDataMap</code> to be associated with the \n     * <code>Trigger</code>.\n     * </p>\n     */\n    void setJobDataMap(JobDataMap jobDataMap);\n\n    /**\n     * The priority of a <code>Trigger</code> acts as a tie breaker such that if \n     * two <code>Trigger</code>s have the same scheduled fire time, then Quartz\n     * will do its best to give the one with the higher priority first access \n     * to a worker thread.\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>5</code>.\n     * </p>\n     * \n     * @see #DEFAULT_PRIORITY\n     */\n    void setPriority(int priority);\n\n    /**\n     * <p>\n     * The time at which the trigger's scheduling should start.  May or may not\n     * be the first actual fire time of the trigger, depending upon the type of\n     * trigger and the settings of the other properties of the trigger.  However\n     * the first actual first time will not be before this date.\n     * </p>\n     * <p>\n     * Setting a value in the past may cause a new trigger to compute a first\n     * fire time that is in the past, which may cause an immediate misfire\n     * of the trigger.\n     * </p>\n     */\n    void setStartTime(Date startTime);\n\n    /**\n     * <p>\n     * Set the time at which the <code>Trigger</code> should quit repeating -\n     * regardless of any remaining repeats (based on the trigger's particular \n     * repeat settings). \n     * </p>\n     * \n     * @see org.quartz.TriggerUtils#computeEndTimeToAllowParticularNumberOfFirings(org.quartz.spi.OperableTrigger, org.quartz.Calendar, int) \n     */\n    void setEndTime(Date endTime);\n\n    /**\n     * <p>\n     * Set the instruction the <code>Scheduler</code> should be given for\n     * handling misfire situations for this <code>Trigger</code>- the\n     * concrete <code>Trigger</code> type that you are using will have\n     * defined a set of additional <code>MISFIRE_INSTRUCTION_XXX</code>\n     * constants that may be passed to this method.\n     * </p>\n     * \n     * <p>\n     * If not explicitly set, the default value is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.\n     * </p>\n     * \n     * @see #MISFIRE_INSTRUCTION_SMART_POLICY\n     * @see org.quartz.spi.OperableTrigger#updateAfterMisfire(org.quartz.Calendar) \n     * @see SimpleTrigger\n     * @see CronTrigger\n     */\n    void setMisfireInstruction(int misfireInstruction);\n\n\n    Object clone();\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/OperableTrigger.java",
    "content": "package org.quartz.spi;\n\nimport java.util.Date;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\npublic interface OperableTrigger extends MutableTrigger {\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Called when the <code>{@link Scheduler}</code> has decided to 'fire'\n     * the trigger (execute the associated <code>Job</code>), in order to\n     * give the <code>Trigger</code> a chance to update itself for its next\n     * triggering (if any).\n     * </p>\n     * \n     * @see #executionComplete(JobExecutionContext, JobExecutionException)\n     */\n    void triggered(Calendar calendar);\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Called by the scheduler at the time a <code>Trigger</code> is first\n     * added to the scheduler, in order to have the <code>Trigger</code>\n     * compute its first fire time, based on any associated calendar.\n     * </p>\n     * \n     * <p>\n     * After this method has been called, <code>getNextFireTime()</code>\n     * should return a valid answer.\n     * </p>\n     * \n     * @return the first time at which the <code>Trigger</code> will be fired\n     *         by the scheduler, which is also the same value <code>getNextFireTime()</code>\n     *         will return (until after the first firing of the <code>Trigger</code>).\n     */\n    Date computeFirstFireTime(Calendar calendar);\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Called after the <code>{@link Scheduler}</code> has executed the\n     * <code>{@link org.quartz.JobDetail}</code> associated with the <code>Trigger</code>\n     * in order to get the final instruction code from the trigger.\n     * </p>\n     * \n     * @param context\n     *          is the <code>JobExecutionContext</code> that was used by the\n     *          <code>Job</code>'s<code>execute(xx)</code> method.\n     * @param result\n     *          is the <code>JobExecutionException</code> thrown by the\n     *          <code>Job</code>, if any (may be null).\n     * @return one of the <code>CompletedExecutionInstruction</code> constants.\n     * \n     * @see CompletedExecutionInstruction\n     * @see #triggered(Calendar)\n     */\n    CompletedExecutionInstruction executionComplete(JobExecutionContext context, JobExecutionException result);\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * To be implemented by the concrete classes that extend this class.\n     * </p>\n     * \n     * <p>\n     * The implementation should update the <code>Trigger</code>'s state\n     * based on the MISFIRE_INSTRUCTION_XXX that was selected when the <code>Trigger</code>\n     * was created.\n     * </p>\n     */\n    void updateAfterMisfire(Calendar cal);\n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * To be implemented by the concrete class.\n     * </p>\n     * \n     * <p>\n     * The implementation should update the <code>Trigger</code>'s state\n     * based on the given new version of the associated <code>Calendar</code>\n     * (the state should be updated so that it's next fire time is appropriate\n     * given the Calendar's new settings). \n     * </p>\n     * \n     * @param cal\n     */\n    void updateWithNewCalendar(Calendar cal, long misfireThreshold);\n\n    \n    /**\n     * <p>\n     * Validates whether the properties of the <code>JobDetail</code> are\n     * valid for submission into a <code>Scheduler</code>.\n     * \n     * @throws IllegalStateException\n     *           if a required property (such as Name, Group, Class) is not\n     *           set.\n     */\n    void validate() throws SchedulerException;\n    \n\n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     * \n     * <p>\n     * Usable by <code>{@link org.quartz.spi.JobStore}</code>\n     * implementations, in order to facilitate 'recognizing' instances of fired\n     * <code>Trigger</code> s as their jobs complete execution.\n     * </p>\n     * \n     *  \n     */\n    void setFireInstanceId(String id);\n    \n    /**\n     * <p>\n     * This method should not be used by the Quartz client.\n     * </p>\n     */\n    String getFireInstanceId();\n\n    \n    void setNextFireTime(Date nextFireTime);\n    \n    void setPreviousFireTime(Date previousFireTime);\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/SchedulerPlugin.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\n/**\n * <p>\n * Provides an interface for a class to become a \"plugin\" to Quartz.\n * </p>\n * \n * <p>\n * Plugins can do virtually anything you wish, though the most interesting ones\n * will obviously interact with the scheduler in some way - either actively: by\n * invoking actions on the scheduler, or passively: by being a <code>JobListener</code>,\n * <code>TriggerListener</code>, and/or <code>SchedulerListener</code>.\n * </p>\n * \n * <p>\n * If you use <code>{@link org.quartz.impl.StdSchedulerFactory}</code> to\n * initialize your Scheduler, it can also create and initialize your plugins -\n * look at the configuration docs for details.\n * </p>\n * \n * <p>\n * If you need direct access your plugin, you can have it explicitly put a \n * reference to itself in the <code>Scheduler</code>'s \n * <code>SchedulerContext</code> as part of its\n * <code>{@link #initialize(String, Scheduler, ClassLoadHelper)}</code> method.\n * </p>\n * \n * @author James House\n */\npublic interface SchedulerPlugin {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Called during creation of the <code>Scheduler</code> in order to give\n     * the <code>SchedulerPlugin</code> a chance to initialize.\n     * </p>\n     * \n     * <p>\n     * At this point, the Scheduler's <code>JobStore</code> is not yet\n     * initialized.\n     * </p>\n     * \n     * <p>\n     * If you need direct access your plugin, for example during <code>Job</code>\n     * execution, you can have this method explicitly put a \n     * reference to this plugin in the <code>Scheduler</code>'s \n     * <code>SchedulerContext</code>.\n     * </p>\n     * \n     * @param name\n     *          The name by which the plugin is identified.\n     * @param scheduler\n     *          The scheduler to which the plugin is registered.\n     * @param loadHelper\n     *            The classLoadHelper the <code>SchedulerFactory</code> is\n     *            actually using\n     * \n     * @throws org.quartz.SchedulerConfigException\n     *           if there is an error initializing.\n     */\n    void initialize(String name, Scheduler scheduler, ClassLoadHelper loadHelper)\n        throws SchedulerException;\n\n    /**\n     * <p>\n     * Called when the associated <code>Scheduler</code> is started, in order\n     * to let the plug-in know it can now make calls into the scheduler if it\n     * needs to.\n     * </p>\n     */\n    void start();\n\n    /**\n     * <p>\n     * Called in order to inform the <code>SchedulerPlugin</code> that it\n     * should free up all of it's resources because the scheduler is shutting\n     * down.\n     * </p>\n     */\n    void shutdown();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/SchedulerSignaler.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport org.quartz.JobKey;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\n\n/**\n * An interface to be used by <code>JobStore</code> instances in order to\n * communicate signals back to the <code>QuartzScheduler</code>.\n * \n * @author jhouse\n */\npublic interface SchedulerSignaler {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    void notifyTriggerListenersMisfired(Trigger trigger);\n\n    void notifySchedulerListenersFinalized(Trigger trigger);\n\n    void notifySchedulerListenersJobDeleted(JobKey jobKey);\n\n    void signalSchedulingChange(long candidateNewNextFireTime);\n\n    void notifySchedulerListenersError(String string, SchedulerException jpe);\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/ThreadExecutor.java",
    "content": "package org.quartz.spi;\n\n/**\n * Allows different strategies for scheduling threads. The {@link #initialize()}\n * method is required to be called before the first call to\n * {@link #execute(Thread)}. The Thread containing the work to be performed is\n * passed to execute and the work is scheduled by the underlying implementation.\n *\n * @author matt.accola\n * @version $Revision$ $Date$\n */\npublic interface ThreadExecutor {\n\n    /**\n     * Submit a task for execution\n     *\n     * @param thread the thread to execute\n     */\n    void execute(Thread thread);\n\n    /**\n     * Initialize any state prior to calling {@link #execute(Thread)}\n     */\n    void initialize();\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/ThreadPool.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.spi;\n\nimport org.quartz.SchedulerConfigException;\n\n/**\n * <p>\n * The interface to be implemented by classes that want to provide a thread\n * pool for the <code>{@link org.quartz.core.QuartzScheduler}</code>'s use.\n * </p>\n *\n * <p>\n * <code>ThreadPool</code> implementation instances should ideally be made\n * for the sole use of Quartz.  Most importantly, when the method\n * <code>blockForAvailableThreads()</code> returns a value of 1 or greater,\n * there must still be at least one available thread in the pool when the\n * method <code>runInThread(Runnable)</code> is called a few moments (or\n * many moments) later.  If this assumption does not hold true, it may\n * result in extra JobStore queries and updates, and if clustering features\n * are being used, it may result in greater imbalance of load.\n * </p>\n *\n * @see org.quartz.core.QuartzScheduler\n *\n * @author James House\n */\npublic interface ThreadPool {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Execute the given <code>{@link java.lang.Runnable}</code> in the next\n     * available <code>Thread</code>.\n     * </p>\n     *\n     * <p>\n     * The implementation of this interface should not throw exceptions unless\n     * there is a serious problem (i.e. a serious misconfiguration). If there\n     * are no immediately available threads <code>false</code> should be returned.\n     * </p>\n     *\n     * @return true, if the runnable was assigned to run on a Thread.\n     */\n    boolean runInThread(Runnable runnable);\n\n    /**\n     * <p>\n     * Determines the number of threads that are currently available in in\n     * the pool.  Useful for determining the number of times\n     * <code>runInThread(Runnable)</code> can be called before returning\n     * false.\n     * </p>\n     *\n     * <p>The implementation of this method should block until there is at\n     * least one available thread.</p>\n     *\n     * @return the number of currently available threads\n     */\n    int blockForAvailableThreads();\n\n    /**\n     * <p>\n     * Must be called before the <code>ThreadPool</code> is\n     * used, in order to give the it a chance to initialize.\n     * </p>\n     * \n     * <p>Typically called by the <code>SchedulerFactory</code>.</p>\n     */\n    void initialize() throws SchedulerConfigException;\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler to inform the <code>ThreadPool</code>\n     * that it should free up all of it's resources because the scheduler is\n     * shutting down.\n     * </p>\n     */\n    void shutdown(boolean waitForJobsToComplete);\n\n    /**\n     * <p>Get the current number of threads in the <code>ThreadPool</code>.</p>\n     */\n    int getPoolSize();\n\n    /**\n     * <p>Inform the <code>ThreadPool</code> of the Scheduler instance's Id,\n     * prior to initialize being invoked.</p>\n     *\n     * @since 1.7\n     */\n    void setInstanceId(String schedInstId);\n\n    /**\n     * <p>Inform the <code>ThreadPool</code> of the Scheduler instance's name,\n     * prior to initialize being invoked.</p>\n     *\n     * @since 1.7\n     */\n    void setInstanceName(String schedName);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/TimeBroker.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport java.util.Date;\n\nimport org.quartz.SchedulerConfigException;\nimport org.quartz.SchedulerException;\n\n/**\n * <p>NOTE: TimeBroker is not currently used in the Quartz code base.</p>\n *\n * <p>\n * The interface to be implemented by classes that want to provide a mechanism\n * by which the <code>{@link org.quartz.core.QuartzScheduler}</code> can\n * reliably determine the current time.\n * </p>\n * \n * <p>\n * In general, the default implementation of this interface (<code>{@link org.quartz.simpl.SimpleTimeBroker}</code>-\n * which simply uses <code>System.getCurrentTimeMillis()</code> )is\n * sufficient. However situations may exist where this default scheme is\n * lacking in its robustness - especially when Quartz is used in a clustered\n * configuration. For example, if one or more of the machines in the cluster\n * has a system time that varies by more than a few seconds from the clocks on\n * the other systems in the cluster, scheduling confusion will result.\n * </p>\n * \n * @see org.quartz.core.QuartzScheduler\n * @deprecated TimeBroker is not currently used in the Quartz code base.\n * @author James House\n */\n@Deprecated\npublic interface TimeBroker {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the current time, as known by the <code>TimeBroker</code>.\n     * </p>\n     * \n     * @throws SchedulerException\n     *           with the error code set to\n     *           SchedulerException.ERR_TIME_BROKER_FAILURE\n     */\n    Date getCurrentTime() throws SchedulerException;\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler before the <code>TimeBroker</code> is\n     * used, in order to give the it a chance to initialize.\n     * </p>\n     */\n    void initialize() throws SchedulerConfigException;\n\n    /**\n     * <p>\n     * Called by the QuartzScheduler to inform the <code>TimeBroker</code>\n     * that it should free up all of it's resources because the scheduler is\n     * shutting down.\n     * </p>\n     */\n    void shutdown();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/TriggerFiredBundle.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.spi;\n\nimport java.util.Date;\n\nimport org.quartz.Calendar;\nimport org.quartz.JobDetail;\n\n/**\n * <p>\n * A simple class (structure) used for returning execution-time data from the\n * JobStore to the <code>QuartzSchedulerThread</code>.\n * </p>\n * \n * @see org.quartz.core.QuartzSchedulerThread\n * \n * @author James House\n */\npublic class TriggerFiredBundle implements java.io.Serializable {\n  \n    private static final long serialVersionUID = -6414106108306999265L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final JobDetail job;\n\n    private final OperableTrigger trigger;\n\n    private final Calendar cal;\n\n    private final boolean jobIsRecovering;\n\n    private final Date fireTime;\n\n    private final Date scheduledFireTime;\n\n    private final Date prevFireTime;\n\n    private final Date nextFireTime;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public TriggerFiredBundle(JobDetail job, OperableTrigger trigger, Calendar cal,\n            boolean jobIsRecovering, Date fireTime, Date scheduledFireTime,\n            Date prevFireTime, Date nextFireTime) {\n        this.job = job;\n        this.trigger = trigger;\n        this.cal = cal;\n        this.jobIsRecovering = jobIsRecovering;\n        this.fireTime = fireTime;\n        this.scheduledFireTime = scheduledFireTime;\n        this.prevFireTime = prevFireTime;\n        this.nextFireTime = nextFireTime;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public JobDetail getJobDetail() {\n        return job;\n    }\n\n    public OperableTrigger getTrigger() {\n        return trigger;\n    }\n\n    public Calendar getCalendar() {\n        return cal;\n    }\n\n    public boolean isRecovering() {\n        return jobIsRecovering;\n    }\n\n    /**\n     * @return Returns the fireTime.\n     */\n    public Date getFireTime() {\n        return fireTime;\n    }\n\n    /**\n     * @return Returns the nextFireTime.\n     */\n    public Date getNextFireTime() {\n        return nextFireTime;\n    }\n\n    /**\n     * @return Returns the prevFireTime.\n     */\n    public Date getPrevFireTime() {\n        return prevFireTime;\n    }\n\n    /**\n     * @return Returns the scheduledFireTime.\n     */\n    public Date getScheduledFireTime() {\n        return scheduledFireTime;\n    }\n\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/TriggerFiredResult.java",
    "content": "package org.quartz.spi;\n\n/**\n * @author lorban\n */\npublic class TriggerFiredResult {\n\n  private TriggerFiredBundle triggerFiredBundle;\n\n  private Exception exception;\n\n  public TriggerFiredResult(TriggerFiredBundle triggerFiredBundle) {\n    this.triggerFiredBundle = triggerFiredBundle;\n  }\n\n  public TriggerFiredResult(Exception exception) {\n    this.exception = exception;\n  }\n\n  public TriggerFiredBundle getTriggerFiredBundle() {\n    return triggerFiredBundle;\n  }\n\n  public Exception getException() {\n    return exception;\n  }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/spi/package.html",
    "content": "<html>\n<head>\n<title>Package org.quartz.spi</title>\n</head>\n<body>\n<p>Contains Service Provider Interfaces that can be implemented by those\nwishing to create and use custom versions of Quartz back-end/behind-the-scenes\nservices.</p>\n\n<br>\n<br>\n<hr>\nSee the <a href=\"http://www.quartz-scheduler.org\">Quartz</a> project\n  for more information.\n\n</body>\n</html>\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/C3p0PoolingConnectionProvider.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.beans.PropertyVetoException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport org.quartz.SchedulerException;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n/**\n * <p>\n * A <code>ConnectionProvider</code> implementation that creates its own\n * pool of connections.\n * </p>\n *\n * <p>\n * This class uses C3PO (http://www.mchange.com/projects/c3p0/index.html) as\n * the underlying pool implementation.</p>\n *\n * @see DBConnectionManager\n * @see ConnectionProvider\n *\n * @author Sharada Jambula\n * @author James House\n * @author Mohammad Rezaei\n */\npublic class C3p0PoolingConnectionProvider implements PoolingConnectionProvider {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * The maximum number of prepared statements that will be cached per connection in the pool.\n     * Depending upon your JDBC Driver this may significantly help performance, or may slightly \n     * hinder performance.   \n     * Default is 120, as Quartz uses over 100 unique statements. 0 disables the feature. \n     */\n    public static final String DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = \"maxCachedStatementsPerConnection\";\n\n    /**\n     * The number of seconds between tests of idle connections - only enabled\n     * if the validation query property is set.  Default is 50 seconds. \n     */\n    public static final String DB_IDLE_VALIDATION_SECONDS = \"idleConnectionValidationSeconds\";\n\n    /**\n     * Whether the database sql query to validate connections should be executed every time \n     * a connection is retrieved from the pool to ensure that it is still valid.  If false,\n     * then validation will occur on check-in.  Default is false. \n     */\n    public static final String DB_VALIDATE_ON_CHECKOUT = \"validateOnCheckout\";\n\n    /** Discard connections after they have been idle this many seconds.  0 disables the feature. Default is 0.*/\n    public static final String DB_DISCARD_IDLE_CONNECTIONS_SECONDS = \"maxIdleTime\";\n\n    /** Default maximum number of database connections in the pool. */\n    public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;\n\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private ComboPooledDataSource datasource;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public C3p0PoolingConnectionProvider(String dbDriver, String dbURL,\n                                         String dbUser, String dbPassword, int maxConnections,\n                                         String dbValidationQuery) throws SQLException, SchedulerException {\n        initialize(\n                dbDriver, dbURL, dbUser, dbPassword,\n                maxConnections, DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION, dbValidationQuery, false, 50, 0);\n    }\n\n    /**\n     * Create a connection pool using the given properties.\n     *\n     * <p>\n     * The properties passed should contain:\n     * </p>\n     * <UL>\n     * <LI>{@link #DB_DRIVER}- The database driver class name\n     * <LI>{@link #DB_URL}- The database URL\n     * <LI>{@link #DB_USER}- The database user\n     * <LI>{@link #DB_PASSWORD}- The database password\n     * <LI>{@link #DB_MAX_CONNECTIONS}- The maximum # connections in the pool,\n     * optional\n     * <LI>{@link #DB_VALIDATION_QUERY}- The sql validation query, optional\n     * </UL>\n     *\n     * @param config\n     *            configuration properties\n     */\n    public C3p0PoolingConnectionProvider(Properties config) throws SchedulerException, SQLException {\n        PropertiesParser cfg = new PropertiesParser(config);\n        initialize(\n                cfg.getStringProperty(DB_DRIVER),\n                cfg.getStringProperty(DB_URL),\n                cfg.getStringProperty(DB_USER, \"\"),\n                cfg.getStringProperty(DB_PASSWORD, \"\"),\n                cfg.getIntProperty(DB_MAX_CONNECTIONS, DEFAULT_DB_MAX_CONNECTIONS),\n                cfg.getIntProperty(DB_MAX_CACHED_STATEMENTS_PER_CONNECTION, DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION),\n                cfg.getStringProperty(DB_VALIDATION_QUERY),\n                cfg.getBooleanProperty(DB_VALIDATE_ON_CHECKOUT, false),\n                cfg.getIntProperty(DB_IDLE_VALIDATION_SECONDS, 50),\n                cfg.getIntProperty(DB_DISCARD_IDLE_CONNECTIONS_SECONDS, 0));\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Create the underlying C3PO ComboPooledDataSource with the \n     * default supported properties.\n     * @throws SchedulerException\n     */\n    private void initialize(\n            String dbDriver,\n            String dbURL,\n            String dbUser,\n            String dbPassword,\n            int maxConnections,\n            int maxStatementsPerConnection,\n            String dbValidationQuery,\n            boolean validateOnCheckout,\n            int idleValidationSeconds,\n            int maxIdleSeconds) throws SQLException, SchedulerException {\n        if (dbURL == null) {\n            throw new SQLException(\n                    \"DBPool could not be created: DB URL cannot be null\");\n        }\n\n        if (dbDriver == null) {\n            throw new SQLException(\n                    \"DBPool '\" + dbURL + \"' could not be created: \" +\n                            \"DB driver class name cannot be null!\");\n        }\n\n        if (maxConnections < 0) {\n            throw new SQLException(\n                    \"DBPool '\" + dbURL + \"' could not be created: \" +\n                            \"Max connections must be greater than zero!\");\n        }\n\n\n        datasource = new ComboPooledDataSource();\n        try {\n            datasource.setDriverClass(dbDriver);\n        } catch (PropertyVetoException e) {\n            throw new SchedulerException(\"Problem setting driver class name on datasource: \" + e.getMessage(), e);\n        }\n        datasource.setJdbcUrl(dbURL);\n        datasource.setUser(dbUser);\n        datasource.setPassword(dbPassword);\n        datasource.setMaxPoolSize(maxConnections);\n        datasource.setMinPoolSize(1);\n        datasource.setMaxIdleTime(maxIdleSeconds);\n        datasource.setMaxStatementsPerConnection(maxStatementsPerConnection);\n\n        if (dbValidationQuery != null) {\n            datasource.setPreferredTestQuery(dbValidationQuery);\n            if(!validateOnCheckout)\n                datasource.setTestConnectionOnCheckin(true);\n            else\n                datasource.setTestConnectionOnCheckout(true);\n            datasource.setIdleConnectionTestPeriod(idleValidationSeconds);\n        }\n    }\n\n    /**\n     * Get the C3PO ComboPooledDataSource created during initialization.\n     *\n     * <p>\n     * This can be used to set additional data source properties in a \n     * subclass's constructor.\n     * </p>\n     */\n    public ComboPooledDataSource getDataSource() {\n        return datasource;\n    }\n\n    public Connection getConnection() throws SQLException {\n        return datasource.getConnection();\n    }\n\n    public void shutdown() throws SQLException {\n        datasource.close();\n    }\n\n    public void initialize() throws SQLException {\n        // do nothing, already initialized during constructor call\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/CircularLossyQueue.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * An implementation of a CircularQueue data-structure.\n * When the number of items added exceeds the maximum capacity, items that were\n * added first are lost.\n *\n * @param <T>\n *            Type of the item's to add in this queue\n *\n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.7\n */\npublic class CircularLossyQueue<T> {\n    private final AtomicReference<T>[] circularArray;\n    private final int maxSize;\n    private int currentIndex = -1;\n    private boolean isFull = false;\n\n    /**\n     * Constructs the circular queue with the specified capacity\n     *\n     * @param size\n     */\n    @SuppressWarnings(\"unchecked\")\n    public CircularLossyQueue(int size) {\n        this.circularArray = new AtomicReference[size];\n        for (int i = 0; i < size; i++) {\n            this.circularArray[i] = new AtomicReference<>();\n        }\n        this.maxSize = size;\n    }\n\n    /**\n     * Adds a new item\n     *\n     * @param newVal\n     */\n    public void push(T newVal) {\n        int index = (++currentIndex) % maxSize;\n        circularArray[index].set(newVal);\n        isFull = isFull || currentIndex == maxSize;\n        currentIndex = index;\n    }\n\n    /**\n     * Returns an array of the current elements in the queue. The order of\n     * elements is in reverse order of the order items were added.\n     *\n     * @param type\n     * @return An array containing the current elements in the queue. The first\n     *         element of the array is the tail of the queue and the last\n     *         element is the head of the queue\n     */\n    public T[] toArray(T[] type) {\n        if (type.length > maxSize) {\n            throw new IllegalArgumentException(\"Size of array passed in cannot be greater than \" + maxSize);\n        }\n\n        int curIndex = currentIndex + maxSize;\n        for (int k = 0; k < type.length; k++) {\n            int index = (curIndex - k) % maxSize;\n            type[k] = circularArray[index].get();\n        }\n        return type;\n    }\n\n    /**\n     * Returns value at the tail of the queue\n     *\n     * @return Value at the tail of the queue\n     */\n    public T peek() {\n        if (currentIndex == -1) {\n            return null;\n        }\n        return circularArray[currentIndex].get();\n    }\n\n    /**\n     * Returns true if the queue is empty, otherwise false\n     *\n     * @return true if the queue is empty, false otherwise\n     */\n    public boolean isEmpty() {\n        return currentIndex == -1;\n    }\n\n    /**\n     * Returns the number of items currently in the queue\n     *\n     * @return the number of items in the queue\n     */\n    public int depth() {\n        return isFull ? maxSize : currentIndex + 1;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/ClassUtils.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.utils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\npublic class ClassUtils {\n\n    \n    public static boolean isAnnotationPresent(Class<?> clazz, Class<? extends Annotation> a) {\n        for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {\n            if (c.isAnnotationPresent(a))\n                return true;\n            if(isAnnotationPresentOnInterfaces(c, a))\n                return true;\n        }\n        return false;\n    }\n\n    private static boolean isAnnotationPresentOnInterfaces(Class<?> clazz, Class<? extends Annotation> a) {\n        for(Class<?> i : clazz.getInterfaces()) {\n            if( i.isAnnotationPresent(a) )\n                return true;\n            if(isAnnotationPresentOnInterfaces(i, a))\n                return true;\n        }\n        \n        return false;\n    }\n\n    public static <T extends Annotation> T getAnnotation(Class<?> clazz, Class<T> aClazz) {\n        //Check class hierarchy\n        for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {\n            T anno = c.getAnnotation(aClazz);\n            if (anno != null) {\n                return anno;\n            }\n        }\n\n        //Check interfaces (breadth first)\n        Queue<Class<?>> q = new LinkedList<>();\n        q.add(clazz);\n        while (!q.isEmpty()) {\n            Class<?> c = q.remove();\n            if (c != null) {\n                if (c.isInterface()) {\n                    T anno = c.getAnnotation(aClazz);\n                    if (anno != null) {\n                        return anno;\n                    }\n                } else {\n                    q.add(c.getSuperclass());\n                }\n                q.addAll(Arrays.asList(c.getInterfaces()));\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/ConnectionProvider.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * Implementations of this interface used by <code>DBConnectionManager</code>\n * to provide connections from various sources.\n * \n * @see DBConnectionManager\n * @see PoolingConnectionProvider\n * @see JNDIConnectionProvider\n * \n * @author Mohammad Rezaei\n */\npublic interface ConnectionProvider {\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * @return connection managed by this provider\n     * @throws SQLException\n     */\n    Connection getConnection() throws SQLException;\n    \n    \n    void shutdown() throws SQLException;\n    \n    void initialize() throws SQLException;\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/DBConnectionManager.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.HashMap;\n\n/**\n * <p>\n * Manages a collection of ConnectionProviders, and provides transparent access\n * to their connections.\n * </p>\n * \n * @see ConnectionProvider\n * @see PoolingConnectionProvider\n * @see JNDIConnectionProvider\n * \n * @author James House\n * @author Sharada Jambula\n * @author Mohammad Rezaei\n */\npublic class DBConnectionManager {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String DB_PROPS_PREFIX = \"org.quartz.db.\";\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private static final DBConnectionManager instance = new DBConnectionManager();\n\n    private final HashMap<String, ConnectionProvider> providers = new HashMap<>();\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Private constructor\n     * </p>\n     *  \n     */\n    private DBConnectionManager() {\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void addConnectionProvider(String dataSourceName,\n            ConnectionProvider provider) {\n        this.providers.put(dataSourceName, provider);\n    }\n\n    /**\n     * Get a database connection from the DataSource with the given name.\n     * \n     * @return a database connection\n     * @exception SQLException\n     *              if an error occurs, or there is no DataSource with the\n     *              given name.\n     */\n    public Connection getConnection(String dsName) throws SQLException {\n        ConnectionProvider provider = providers.get(dsName);\n        if (provider == null) {\n            throw new SQLException(\"There is no DataSource named '\"\n                    + dsName + \"'\");\n        }\n\n        return provider.getConnection();\n    }\n\n    /**\n     * Get the class instance.\n     * \n     * @return an instance of this class\n     */\n    public static DBConnectionManager getInstance() {\n        // since the instance variable is initialized at class loading time,\n        // it's not necessary to synchronize this method */\n        return instance;\n    }\n\n    /**\n     * Shuts down database connections from the DataSource with the given name,\n     * if applicable for the underlying provider.\n     *\n     * @exception SQLException\n     *              if an error occurs, or there is no DataSource with the\n     *              given name.\n     */\n    public void shutdown(String dsName) throws SQLException {\n\n        ConnectionProvider provider = (ConnectionProvider) providers\n        .get(dsName);\n        if (provider == null) {\n            throw new SQLException(\"There is no DataSource named '\"\n                    + dsName + \"'\");\n        }\n\n        provider.shutdown();\n\n    }\n\n    ConnectionProvider getConnectionProvider(String key) {\n        return providers.get(key);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/DirtyFlagMap.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.utils;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * <p>\n * An implementation of <code>Map</code> that wraps another <code>Map</code>\n * and flags itself 'dirty' when it is modified.\n * </p>\n *\n * @author James House\n */\npublic class DirtyFlagMap<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    private static final long serialVersionUID = 1433884852607126222L;\n\n    private boolean dirty = false;\n    private Map<K,V> map;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Create a DirtyFlagMap that 'wraps' a <code>HashMap</code>.\n     * </p>\n     *\n     * @see java.util.HashMap\n     */\n    public DirtyFlagMap() {\n        map = new HashMap<>();\n    }\n\n    /**\n     * <p>\n     * Create a DirtyFlagMap that 'wraps' a <code>HashMap</code> that has the\n     * given initial capacity.\n     * </p>\n     *\n     * @see java.util.HashMap\n     */\n    public DirtyFlagMap(final int initialCapacity) {\n        map = new HashMap<>(initialCapacity);\n    }\n\n    /**\n     * <p>\n     * Create a DirtyFlagMap that 'wraps' a <code>HashMap</code> that has the\n     * given initial capacity and load factor.\n     * </p>\n     *\n     * @see java.util.HashMap\n     */\n    public DirtyFlagMap(final int initialCapacity, final float loadFactor) {\n        map = new HashMap<>(initialCapacity, loadFactor);\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Clear the 'dirty' flag (set dirty flag to <code>false</code>).\n     * </p>\n     */\n    public void clearDirtyFlag() {\n        dirty = false;\n    }\n\n    /**\n     * <p>\n     * Determine whether the <code>Map</code> is flagged dirty.\n     * </p>\n     */\n    public boolean isDirty() {\n        return dirty;\n    }\n\n    /**\n     * <p>\n     * Get a direct handle to the underlying Map.\n     * </p>\n     */\n    public Map<K,V> getWrappedMap() {\n        return map;\n    }\n\n    public void clear() {\n        if (!map.isEmpty()) {\n            dirty = true;\n        }\n        map.clear();\n    }\n\n    public boolean containsKey(final Object key) {\n        return map.containsKey(key);\n    }\n\n    public boolean containsValue(final Object val) {\n        return map.containsValue(val);\n    }\n\n    public Set<Entry<K,V>> entrySet() {\n        return new DirtyFlagMapEntrySet(map.entrySet());\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == null || !(obj instanceof DirtyFlagMap)) {\n            return false;\n        }\n\n        return map.equals(((DirtyFlagMap<?,?>) obj).getWrappedMap());\n    }\n\n    @Override\n    public int hashCode()\n    {\n        return map.hashCode();\n    }\n\n    public V get(final Object key) {\n        return map.get(key);\n    }\n\n    public boolean isEmpty() {\n        return map.isEmpty();\n    }\n\n    public Set<K> keySet() {\n        return new DirtyFlagSet<>(map.keySet());\n    }\n\n    public V put(final K key, final V val) {\n        dirty = true;\n\n        return map.put(key, val);\n    }\n\n    public void putAll(final Map<? extends K, ? extends V> t) {\n        if (!t.isEmpty()) {\n            dirty = true;\n        }\n\n        map.putAll(t);\n    }\n\n    public V remove(final Object key) {\n        V obj = map.remove(key);\n\n        if (obj != null) {\n            dirty = true;\n        }\n\n        return obj;\n    }\n\n    public int size() {\n        return map.size();\n    }\n\n    public Collection<V> values() {\n        return new DirtyFlagCollection<>(map.values());\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\") // suppress warnings on generic cast of super.clone() and map.clone() lines.\n    public Object clone() {\n        DirtyFlagMap<K,V> copy;\n        try {\n            copy = (DirtyFlagMap<K,V>) super.clone();\n            if (map instanceof HashMap) {\n                copy.map = (Map<K,V>)((HashMap<K,V>)map).clone();\n            }\n        } catch (CloneNotSupportedException ex) {\n            throw new IncompatibleClassChangeError(\"Not Cloneable.\");\n        }\n\n        return copy;\n    }\n\n    /**\n     * Wrap a Collection so we can mark the DirtyFlagMap as dirty if\n     * the underlying Collection is modified.\n     */\n    private class DirtyFlagCollection<T> implements Collection<T> {\n        private final Collection<T> collection;\n\n        public DirtyFlagCollection(final Collection<T> c) {\n            collection = c;\n        }\n\n        protected Collection<T> getWrappedCollection() {\n            return collection;\n        }\n\n        public Iterator<T> iterator() {\n            return new DirtyFlagIterator<>(collection.iterator());\n        }\n\n        public boolean remove(final Object o) {\n            boolean removed = collection.remove(o);\n            if (removed) {\n                dirty = true;\n            }\n            return removed;\n        }\n\n        public boolean removeAll(final Collection<?> c) {\n            boolean changed = collection.removeAll(c);\n            if (changed) {\n                dirty = true;\n            }\n            return changed;\n        }\n\n        public boolean retainAll(final Collection<?> c) {\n            boolean changed = collection.retainAll(c);\n            if (changed) {\n                dirty = true;\n            }\n            return changed;\n        }\n\n        public void clear() {\n            if (!collection.isEmpty()) {\n                dirty = true;\n            }\n            collection.clear();\n        }\n\n        // Pure wrapper methods\n        public int size() { return collection.size(); }\n        public boolean isEmpty() { return collection.isEmpty(); }\n        public boolean contains(final Object o) { return collection.contains(o); }\n        public boolean add(final T o) { return collection.add(o); } // Not supported\n        public boolean addAll(final Collection<? extends T> c) { return collection.addAll(c); } // Not supported\n        public boolean containsAll(final Collection<?> c) { return collection.containsAll(c); }\n        public Object[] toArray() { return collection.toArray(); }\n        public <U> U[] toArray(final U[] array) { return collection.toArray(array); }\n    }\n\n    /**\n     * Wrap a Set so we can mark the DirtyFlagMap as dirty if\n     * the underlying Collection is modified.\n     */\n    private class DirtyFlagSet<T> extends DirtyFlagCollection<T> implements Set<T> {\n        public DirtyFlagSet(final Set<T> set) {\n            super(set);\n        }\n\n        protected Set<T> getWrappedSet() {\n            return (Set<T>)getWrappedCollection();\n        }\n    }\n\n    /**\n     * Wrap an Iterator so that we can mark the DirtyFlagMap as dirty if an\n     * element is removed.\n     */\n    private class DirtyFlagIterator<T> implements Iterator<T> {\n        private final Iterator<T> iterator;\n\n        public DirtyFlagIterator(final Iterator<T> iterator) {\n            this.iterator = iterator;\n        }\n\n        public void remove() {\n            dirty = true;\n            iterator.remove();\n        }\n\n        // Pure wrapper methods\n        public boolean hasNext() { return iterator.hasNext(); }\n        public T next() { return iterator.next(); }\n    }\n\n    /**\n     * Wrap a Map.Entry Set so we can mark the Map as dirty if\n     * the Set is modified, and return Map.Entry objects\n     * wrapped in the <code>DirtyFlagMapEntry</code> class.\n     */\n    private class DirtyFlagMapEntrySet extends DirtyFlagSet<Map.Entry<K,V>> {\n\n        public DirtyFlagMapEntrySet(final Set<Map.Entry<K,V>> set) {\n            super(set);\n        }\n\n        @Override\n        public Iterator<Map.Entry<K,V>> iterator() {\n            return new DirtyFlagMapEntryIterator(getWrappedSet().iterator());\n        }\n\n        @Override\n        public Object[] toArray() {\n            return toArray(new Object[super.size()]);\n        }\n\n        @SuppressWarnings(\"unchecked\") // suppress warnings on both U[] and U casting.\n        @Override\n        public <U> U[] toArray(final U[] array) {\n            if (!array.getClass().getComponentType().isAssignableFrom(Entry.class)) {\n                throw new IllegalArgumentException(\"Array must be of type assignable from Map.Entry\");\n            }\n\n            int size = super.size();\n\n            U[] result =\n                array.length < size ?\n                    (U[])Array.newInstance(array.getClass().getComponentType(), size) : array;\n\n            Iterator<Map.Entry<K,V>> entryIter = iterator(); // Will return DirtyFlagMapEntry objects\n            for (int i = 0; i < size; i++) {\n                result[i] = ( U ) entryIter.next();\n            }\n\n            if (result.length > size) {\n                result[size] = null;\n            }\n\n            return result;\n        }\n    }\n\n    /**\n     * Wrap an Iterator over Map.Entry objects so that we can\n     * mark the Map as dirty if an element is removed or modified.\n     */\n    private class DirtyFlagMapEntryIterator extends DirtyFlagIterator<Map.Entry<K,V>> {\n        public DirtyFlagMapEntryIterator(final Iterator<Map.Entry<K,V>> iterator) {\n            super(iterator);\n        }\n\n        @Override\n        public DirtyFlagMapEntry next() {\n            return new DirtyFlagMapEntry(super.next());\n        }\n    }\n\n    /**\n     * Wrap a Map.Entry so we can mark the Map as dirty if\n     * a value is set.\n     */\n    private class DirtyFlagMapEntry implements Map.Entry<K,V> {\n        private final Map.Entry<K,V> entry;\n\n        public DirtyFlagMapEntry(final Map.Entry<K,V> entry) {\n            this.entry = entry;\n        }\n\n        public V setValue(final V o) {\n            dirty = true;\n            return entry.setValue(o);\n        }\n\n        // Pure wrapper methods\n        public K getKey() { return entry.getKey(); }\n        public V getValue() { return entry.getValue(); }\n        public boolean equals(Object o) { return entry.equals(o); }\n    }\n}\n\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/FindbugsSuppressWarnings.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.utils;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR,\n         ElementType.LOCAL_VARIABLE, ElementType.PACKAGE })\n@Retention(RetentionPolicy.CLASS)\npublic @interface FindbugsSuppressWarnings {\n\n  String[] value() default {};\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/HikariCpPoolingConnectionProvider.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.quartz.SchedulerException;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\n/**\n * <p>\n * A <code>ConnectionProvider</code> implementation that creates its own\n * pool of connections.\n * </p>\n *\n * <p>\n * This class uses HikariCP (https://brettwooldridge.github.io/HikariCP/) as\n * the underlying pool implementation.</p>\n *\n * @see DBConnectionManager\n * @see ConnectionProvider\n *\n * @author Ludovic Orban\n */\npublic class HikariCpPoolingConnectionProvider implements PoolingConnectionProvider {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constants.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /** This pooling provider name. */\n    public static final String POOLING_PROVIDER_NAME = \"hikaricp\";\n\n    /** Discard connections after they have been idle this many seconds.  0 disables the feature. Default is 0.*/\n    private static final String DB_DISCARD_IDLE_CONNECTIONS_SECONDS = \"discardIdleConnectionsSeconds\";\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Data members.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private HikariDataSource datasource;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public HikariCpPoolingConnectionProvider(String dbDriver, String dbURL,\n                                             String dbUser, String dbPassword, int maxConnections,\n                                             String dbValidationQuery) throws SQLException, SchedulerException {\n        initialize(\n                dbDriver, dbURL, dbUser, dbPassword,\n                maxConnections, dbValidationQuery, 0);\n    }\n\n    /**\n     * Create a connection pool using the given properties.\n     *\n     * <p>\n     * The properties passed should contain:\n     * </p>\n     * <UL>\n     * <LI>{@link #DB_DRIVER}- The database driver class name\n     * <LI>{@link #DB_URL}- The database URL\n     * <LI>{@link #DB_USER}- The database user\n     * <LI>{@link #DB_PASSWORD}- The database password\n     * <LI>{@link #DB_MAX_CONNECTIONS}- The maximum # connections in the pool,\n     * optional\n     * <LI>{@link #DB_VALIDATION_QUERY}- The sql validation query, optional\n     * </UL>\n     *\n     * @param config\n     *            configuration properties\n     */\n    public HikariCpPoolingConnectionProvider(Properties config) throws SchedulerException, SQLException {\n        PropertiesParser cfg = new PropertiesParser(config);\n        initialize(\n                cfg.getStringProperty(DB_DRIVER),\n                cfg.getStringProperty(DB_URL),\n                cfg.getStringProperty(DB_USER, \"\"),\n                cfg.getStringProperty(DB_PASSWORD, \"\"),\n                cfg.getIntProperty(DB_MAX_CONNECTIONS, DEFAULT_DB_MAX_CONNECTIONS),\n                cfg.getStringProperty(DB_VALIDATION_QUERY),\n                cfg.getIntProperty(DB_DISCARD_IDLE_CONNECTIONS_SECONDS, 0));\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Create the underlying C3PO ComboPooledDataSource with the \n     * default supported properties.\n     * @throws SchedulerException\n     */\n    private void initialize(\n            String dbDriver,\n            String dbURL,\n            String dbUser,\n            String dbPassword,\n            int maxConnections,\n            String dbValidationQuery,\n            int maxIdleSeconds) throws SQLException, SchedulerException {\n        if (dbURL == null) {\n            throw new SQLException(\n                    \"DBPool could not be created: DB URL cannot be null\");\n        }\n\n        if (dbDriver == null) {\n            throw new SQLException(\n                    \"DBPool '\" + dbURL + \"' could not be created: \" +\n                            \"DB driver class name cannot be null!\");\n        }\n\n        if (maxConnections < 0) {\n            throw new SQLException(\n                    \"DBPool '\" + dbURL + \"' could not be created: \" +\n                            \"Max connections must be greater than zero!\");\n        }\n\n\n        datasource = new HikariDataSource();\n        datasource.setDriverClassName(dbDriver);\n        datasource.setJdbcUrl(dbURL);\n        datasource.setUsername(dbUser);\n        datasource.setPassword(dbPassword);\n        datasource.setMaximumPoolSize(maxConnections);\n        datasource.setIdleTimeout(maxIdleSeconds);\n\n        if (dbValidationQuery != null) {\n            datasource.setConnectionTestQuery(dbValidationQuery);\n        }\n    }\n\n    /**\n     * Get the HikariCP HikariDataSource created during initialization.\n     *\n     * <p>\n     * This can be used to set additional data source properties in a \n     * subclass's constructor.\n     * </p>\n     */\n    public HikariDataSource getDataSource() {\n        return datasource;\n    }\n\n    public Connection getConnection() throws SQLException {\n        return datasource.getConnection();\n    }\n\n    public void shutdown() throws SQLException {\n        datasource.close();\n    }\n\n    public void initialize() throws SQLException {\n        // do nothing, already initialized during constructor call\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/JNDIConnectionProvider.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.sql.DataSource;\nimport javax.sql.XADataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * A <code>ConnectionProvider</code> that provides connections from a <code>DataSource</code>\n * that is managed by an application server, and made available via JNDI.\n * </p>\n * \n * @see DBConnectionManager\n * @see ConnectionProvider\n * @see PoolingConnectionProvider\n * \n * @author James House\n * @author Sharada Jambula\n * @author Mohammad Rezaei\n * @author Patrick Lightbody\n * @author Srinivas Venkatarangaiah\n */\npublic class JNDIConnectionProvider implements ConnectionProvider {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final String url;\n\n    private Properties props;\n\n    private Object datasource;\n\n    private boolean alwaysLookup;\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Constructor\n     * \n     * @param jndiUrl\n     *          The url for the datasource\n     */\n    public JNDIConnectionProvider(String jndiUrl, boolean alwaysLookup) {\n        this.url = jndiUrl;\n        this.alwaysLookup = alwaysLookup;\n        init();\n    }\n\n    /**\n     * Constructor\n     * \n     * @param jndiUrl\n     *          The URL for the DataSource\n     * @param jndiProps\n     *          The JNDI properties to use when establishing the InitialContext\n     *          for the lookup of the given URL.\n     */\n    public JNDIConnectionProvider(String jndiUrl, Properties jndiProps,\n            boolean alwaysLookup) {\n        this.url = jndiUrl;\n        this.props = jndiProps;\n        this.alwaysLookup = alwaysLookup;\n        init();\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    private void init() {\n\n        if (!isAlwaysLookup()) {\n            Context ctx = null;\n            try {\n                ctx = (props != null) ? new InitialContext(props) : new InitialContext(); \n\n                datasource = (DataSource) ctx.lookup(url);\n            } catch (Exception e) {\n                getLog().error(\"Error looking up datasource: {}\", e.getMessage(), e);\n            } finally {\n                if (ctx != null) {\n                    try { ctx.close(); } catch(Exception ignore) {}\n                }\n            }\n        }\n    }\n\n    public Connection getConnection() throws SQLException {\n        Context ctx = null;\n        try {\n            Object ds = this.datasource;\n\n            if (ds == null || isAlwaysLookup()) {\n                ctx = (props != null) ? new InitialContext(props): new InitialContext(); \n\n                ds = ctx.lookup(url);\n                if (!isAlwaysLookup()) {\n                    this.datasource = ds;\n                }\n            }\n\n            if (ds == null) {\n                throw new SQLException( \"There is no object at the JNDI URL '\" + url + \"'\");\n            }\n\n            if (ds instanceof XADataSource) {\n                return (((XADataSource) ds).getXAConnection().getConnection());\n            } else if (ds instanceof DataSource) { \n                return ((DataSource) ds).getConnection();\n            } else {\n                throw new SQLException(\"Object at JNDI URL '\" + url + \"' is not a DataSource.\");\n            }\n        } catch (Exception e) {\n            this.datasource = null;\n            throw new SQLException(\n                    \"Could not retrieve datasource via JNDI url '\" + url + \"' \"\n                            + e.getClass().getName() + \": \" + e.getMessage());\n        } finally {\n            if (ctx != null) {\n                try { ctx.close(); } catch(Exception ignore) {}\n            }\n        }\n    }\n\n    public boolean isAlwaysLookup() {\n        return alwaysLookup;\n    }\n\n    public void setAlwaysLookup(boolean b) {\n        alwaysLookup = b;\n    }\n\n    /* \n     * @see org.quartz.utils.ConnectionProvider#shutdown()\n     */\n    public void shutdown() throws SQLException {\n        // do nothing\n    }\n\n    public void initialize() throws SQLException {\n        // do nothing, already initialized during constructor call\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/Key.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.io.Serializable;\nimport java.util.UUID;\n\n\n/**\n * <p>\n * Object representing a job or trigger key.\n * </p>\n * \n * @author <a href=\"mailto:jeff@binaryfeed.org\">Jeffrey Wescott</a>\n */\npublic class Key<T>  implements Serializable, Comparable<Key<T>> {\n  \n    private static final long serialVersionUID = -7141167957642391350L;\n\n    /**\n     * The default group for scheduling entities, with the value \"DEFAULT\".\n     */\n    public static final String DEFAULT_GROUP = \"DEFAULT\";\n\n    private final String name;\n    private final String group;\n    \n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Construct a new key with the given name and group.\n     * \n     * @param name\n     *          the name\n     * @param group\n     *          the group\n     */\n    public Key(String name, String group) {\n        if(name == null)\n            throw new IllegalArgumentException(\"Name cannot be null.\");\n        this.name = name;\n        if(group != null)\n            this.group = group;\n        else\n            this.group = DEFAULT_GROUP;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Get the name portion of the key.\n     * </p>\n     * \n     * @return the name\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * <p>\n     * Get the group portion of the key.\n     * </p>\n     * \n     * @return the group\n     */\n    public String getGroup() {\n        return group;\n    }\n\n    /**\n     * <p>\n     * Return the string representation of the key. The format will be:\n     * &lt;group&gt;.&lt;name&gt;.\n     * </p>\n     * \n     * @return the string representation of the key\n     */\n    @Override\n    public String toString() {\n        return getGroup() + '.' + getName();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + group.hashCode();\n        result = prime * result + name.hashCode();\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        @SuppressWarnings(\"unchecked\")\n        Key<T> other = (Key<T>) obj;\n        if (!group.equals(other.group))\n            return false;\n        return name.equals(other.name);\n    }\n\n    public int compareTo(Key<T> o) {\n        \n        if(group.equals(DEFAULT_GROUP) && !o.group.equals(DEFAULT_GROUP))\n            return -1;\n        if(!group.equals(DEFAULT_GROUP) && o.group.equals(DEFAULT_GROUP))\n            return 1;\n            \n        int r = group.compareTo(o.getGroup());\n        if(r != 0)\n            return r;\n        \n        return name.compareTo(o.getName());\n    }\n    \n    public static String createUniqueName(String group) {\n        if(group == null)\n            group = DEFAULT_GROUP;\n        \n        String n1 = UUID.randomUUID().toString();\n        String n2 = UUID.nameUUIDFromBytes(group.getBytes()).toString();\n        \n        return String.format(\"%s-%s\", n2.substring(24), n1);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/PoolingConnectionProvider.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.utils;\n\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * <code>ConnectionProvider</code>s supporting pooling of connections.\n * </p>\n *\n * <p>\n * Implementations must pool connections.\n * </p>\n *\n * @see DBConnectionManager\n * @see ConnectionProvider\n * @author Ludovic Orban\n */\npublic interface PoolingConnectionProvider extends ConnectionProvider {\n\n    /** The pooling provider. */\n    String POOLING_PROVIDER = \"provider\";\n\n    /** The c3p0 pooling provider. */\n    String POOLING_PROVIDER_C3P0 = \"c3p0\";\n\n    /** The Hikari pooling provider. */\n    String POOLING_PROVIDER_HIKARICP = \"hikaricp\";\n\n    /** The JDBC database driver. */\n    String DB_DRIVER = \"driver\";\n\n    /** The JDBC database URL. */\n    String DB_URL = \"URL\";\n\n    /** The database user name. */\n    String DB_USER = \"user\";\n\n    /** The database user password. */\n    String DB_PASSWORD = \"password\";\n\n    /** The maximum number of database connections to have in the pool.  Default is 10. */\n    String DB_MAX_CONNECTIONS = \"maxConnections\";\n\n    /**\n     * The database sql query to execute every time a connection is returned\n     * to the pool to ensure that it is still valid.\n     */\n    String DB_VALIDATION_QUERY = \"validationQuery\";\n\n    /** Default maximum number of database connections in the pool. */\n    int DEFAULT_DB_MAX_CONNECTIONS = 10;\n\n\n    DataSource getDataSource();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/PropertiesParser.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils;\n\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.StringTokenizer;\n\n/**\n * <p>\n * This is an utility class used to parse the properties.\n * </p>\n * \n * @author James House\n */\npublic class PropertiesParser {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    Properties props;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public PropertiesParser(Properties props) {\n        this.props = props;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public Properties getUnderlyingProperties() {\n        return props;\n    }\n\n    /**\n     * Get the trimmed String value of the property with the given \n     * <code>name</code>.  If the value the empty String (after\n     * trimming), then it returns null.\n     */\n    public String getStringProperty(String name) {\n        return getStringProperty(name, null);\n    }\n\n    /**\n     * Get the trimmed String value of the property with the given \n     * <code>name</code> or the given default value if the value is \n     * null or empty after trimming.\n     */\n    public String getStringProperty(String name, String def) {\n        String val = props.getProperty(name, def);\n        if (val == null) {\n            return def;\n        }\n        \n        val = val.trim();\n        \n        return (val.isEmpty()) ? def : val;\n    }\n\n    public String[] getStringArrayProperty(String name) {\n        return getStringArrayProperty(name, null);\n    }\n\n    public String[] getStringArrayProperty(String name, String[] def) {\n        String vals = getStringProperty(name);\n        if (vals == null) {\n            return def;\n        }\n\n        StringTokenizer stok = new StringTokenizer(vals, \",\");\n        ArrayList<String> strs = new ArrayList<>();\n        try {\n            while (stok.hasMoreTokens()) {\n                strs.add(stok.nextToken().trim());\n            }\n            \n            return (String[])strs.toArray(new String[strs.size()]);\n        } catch (Exception e) {\n            return def;\n        }\n    }\n\n    public boolean getBooleanProperty(String name) {\n        return getBooleanProperty(name, false);\n    }\n\n    public boolean getBooleanProperty(String name, boolean def) {\n        String val = getStringProperty(name);\n        \n        return (val == null) ? def : Boolean.parseBoolean(val);\n    }\n\n    public byte getByteProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Byte.parseByte(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public byte getByteProperty(String name, byte def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Byte.parseByte(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public char getCharProperty(String name) {\n        return getCharProperty(name, '\\0');\n    }\n\n    public char getCharProperty(String name, char def) {\n        String param = getStringProperty(name);\n        return  (param == null) ? def : param.charAt(0);\n    }\n\n    public double getDoubleProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Double.parseDouble(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public double getDoubleProperty(String name, double def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Double.parseDouble(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public float getFloatProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Float.parseFloat(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public float getFloatProperty(String name, float def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Float.parseFloat(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public int getIntProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Integer.parseInt(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public int getIntProperty(String name, int def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Integer.parseInt(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public int[] getIntArrayProperty(String name) throws NumberFormatException {\n        return getIntArrayProperty(name, null);\n    }\n\n    public int[] getIntArrayProperty(String name, int[] def)\n        throws NumberFormatException {\n        String vals = getStringProperty(name);\n        if (vals == null) {\n            return def;\n        }\n\n        StringTokenizer stok = new StringTokenizer(vals, \",\");\n        ArrayList<Integer> ints = new ArrayList<>();\n        try {\n            while (stok.hasMoreTokens()) {\n                try {\n                    ints.add(Integer.valueOf(stok.nextToken().trim()));\n                } catch (NumberFormatException nfe) {\n                    throw new NumberFormatException(\" '\" + vals + \"'\");\n                }\n            }\n                        \n            int[] outInts = new int[ints.size()];\n            for (int i = 0; i < ints.size(); i++) {\n                outInts[i] = ints.get(i);\n            }\n            return outInts;\n        } catch (Exception e) {\n            return def;\n        }\n    }\n\n    public long getLongProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Long.parseLong(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public long getLongProperty(String name, long def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Long.parseLong(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public short getShortProperty(String name) throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            throw new NumberFormatException(\" null string\");\n        }\n\n        try {\n            return Short.parseShort(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public short getShortProperty(String name, short def)\n        throws NumberFormatException {\n        String val = getStringProperty(name);\n        if (val == null) {\n            return def;\n        }\n\n        try {\n            return Short.parseShort(val);\n        } catch (NumberFormatException nfe) {\n            throw new NumberFormatException(\" '\" + val + \"'\");\n        }\n    }\n\n    public String[] getPropertyGroups(String prefix) {\n        Enumeration<?> keys = props.propertyNames();\n        HashSet<String> groups = new HashSet<>(10);\n\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n\n        while (keys.hasMoreElements()) {\n            String key = (String) keys.nextElement();\n            if (key.startsWith(prefix)) {\n                String groupName = key.substring(prefix.length(), key.indexOf(\n                        '.', prefix.length()));\n                groups.add(groupName);\n            }\n        }\n\n        return (String[]) groups.toArray(new String[groups.size()]);\n    }\n\n    public Properties getPropertyGroup(String prefix) {\n        return getPropertyGroup(prefix, false, null);\n    }\n\n    public Properties getPropertyGroup(String prefix, boolean stripPrefix) {\n        return getPropertyGroup(prefix, stripPrefix, null);\n    }\n\n    /**\n     * Get all properties that start with the given prefix.  \n     * \n     * @param prefix The prefix for which to search.  If it does not end in \n     *      a \".\" then one will be added to it for search purposes.\n     * @param stripPrefix Whether to strip off the given <code>prefix</code>\n     *      in the result's keys.\n     * @param excludedPrefixes Optional array of fully qualified prefixes to\n     *      exclude.  For example if <code>prefix</code> is \"a.b.c\", then \n     *      <code>excludedPrefixes</code> might be \"a.b.c.ignore\".\n     *      \n     * @return Group of <code>Properties</code> that start with the given prefix, \n     *      optionally have that prefix removed, and do not include properties \n     *      that start with one of the given excluded prefixes.\n     */\n    public Properties getPropertyGroup(String prefix, boolean stripPrefix, String[] excludedPrefixes) {\n        Enumeration<?> keys = props.propertyNames();\n        Properties group = new Properties();\n\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n\n        while (keys.hasMoreElements()) {\n            String key = (String) keys.nextElement();\n            if (key.startsWith(prefix)) {\n                \n                boolean exclude = false;\n                if (excludedPrefixes != null) {\n                    for (int i = 0; (i < excludedPrefixes.length) && (!exclude); i++) {\n                        exclude = key.startsWith(excludedPrefixes[i]);\n                    }\n                }\n\n                if (!exclude) {\n                    String value = getStringProperty(key, \"\");\n                    \n                    if (stripPrefix) { \n                        group.put(key.substring(prefix.length()), value);\n                    } else {\n                        group.put(key, value);\n                    }\n                }\n            }\n        }\n\n        return group;\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/StringKeyDirtyFlagMap.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.utils;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * An implementation of <code>Map</code> that wraps another <code>Map</code>\n * and flags itself 'dirty' when it is modified, enforces that all keys are\n * Strings. \n * </p>\n * \n * <p>\n * All allowsTransientData flag related methods are deprecated as of version 1.6.\n * </p>\n */\npublic class StringKeyDirtyFlagMap extends DirtyFlagMap<String, Object> {\n    private static final long serialVersionUID = -9076749120524952280L;\n    \n    /**\n     * @deprecated JDBCJobStores no longer prune out transient data.  If you\n     * include non-Serializable values in the Map, you will now get an \n     * exception when attempting to store it in a database.\n     */\n    @Deprecated\n    private boolean allowsTransientData = false;\n\n    public StringKeyDirtyFlagMap() {\n        super();\n    }\n\n    public StringKeyDirtyFlagMap(int initialCapacity) {\n        super(initialCapacity);\n    }\n\n    public StringKeyDirtyFlagMap(int initialCapacity, float loadFactor) {\n        super(initialCapacity, loadFactor);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return super.equals(obj);\n    }\n\n    @Override\n    public int hashCode()\n    {\n        return getWrappedMap().hashCode();\n    }\n    \n    /**\n     * Get a copy of the Map's String keys in an array of Strings.\n     */\n    public String[] getKeys() {\n        return keySet().toArray(new String[size()]);\n    }\n\n    /**\n     * Tell the <code>StringKeyDirtyFlagMap</code> that it should\n     * allow non-<code>Serializable</code> values.  Enforces that the Map \n     * doesn't already include transient data.\n     * \n     * @deprecated JDBCJobStores no longer prune out transient data.  If you\n     * include non-Serializable values in the Map, you will now get an \n     * exception when attempting to store it in a database.\n     */\n    @Deprecated\n    public void setAllowsTransientData(boolean allowsTransientData) {\n    \n        if (containsTransientData() && !allowsTransientData) {\n            throw new IllegalStateException(\n                \"Cannot set property 'allowsTransientData' to 'false' \"\n                    + \"when data map contains non-serializable objects.\");\n        }\n    \n        this.allowsTransientData = allowsTransientData;\n    }\n\n    /**\n     * Whether the <code>StringKeyDirtyFlagMap</code> allows \n     * non-<code>Serializable</code> values.\n     * \n     * @deprecated JDBCJobStores no longer prune out transient data.  If you\n     * include non-Serializable values in the Map, you will now get an \n     * exception when attempting to store it in a database.\n     */\n    @Deprecated\n    public boolean getAllowsTransientData() {\n        return allowsTransientData;\n    }\n\n    /**\n     * Determine whether any values in this Map do not implement \n     * <code>Serializable</code>.  Always returns false if this Map\n     * is flagged to not allow transient data.\n     * \n     * @deprecated JDBCJobStores no longer prune out transient data.  If you\n     * include non-Serializable values in the Map, you will now get an \n     * exception when attempting to store it in a database.\n     */\n    @Deprecated\n    public boolean containsTransientData() {\n        if (!getAllowsTransientData()) { // short circuit...\n            return false;\n        }\n    \n        String[] keys = getKeys();\n        for (String key : keys) {\n            Object o = super.get(key);\n            if (!(o instanceof Serializable)) {\n                return true;\n            }\n        }\n    \n        return false;\n    }\n\n    /**\n     * Removes any data values in the map that are non-Serializable.  Does \n     * nothing if this Map does not allow transient data.\n     * \n     * @deprecated JDBCJobStores no longer prune out transient data.  If you\n     * include non-Serializable values in the Map, you will now get an \n     * exception when attempting to store it in a database.\n     */\n    @Deprecated\n    public void removeTransientData() {\n        if (!getAllowsTransientData()) { // short circuit...\n            return;\n        }\n    \n        String[] keys = getKeys();\n        for (String key : keys) {\n            Object o = super.get(key);\n            if (!(o instanceof Serializable)) {\n                remove(key);\n            }\n        }\n    }\n\n    // Due to Generic enforcement, this override method is no longer needed.\n//    /**\n//     * <p>\n//     * Adds the name-value pairs in the given <code>Map</code> to the \n//     * <code>StringKeyDirtyFlagMap</code>.\n//     * </p>\n//     * \n//     * <p>\n//     * All keys must be <code>String</code>s.\n//     * </p>\n//     */\n//    @Override\n//    public void putAll(Map<String, Object> map) {\n//        for (Iterator<?> entryIter = map.entrySet().iterator(); entryIter.hasNext();) {\n//            Map.Entry<?,?> entry = (Map.Entry<?,?>) entryIter.next();\n//            \n//            // will throw IllegalArgumentException if key is not a String\n//            put(entry.getKey(), entry.getValue());\n//        }\n//    }\n\n    /**\n     * <p>\n     * Adds the given <code>int</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, int value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>long</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, long value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>float</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, float value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>double</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, double value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>boolean</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, boolean value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>char</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, char value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>String</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    public void put(String key, String value) {\n        super.put(key, value);\n    }\n\n    /**\n     * <p>\n     * Adds the given <code>Object</code> value to the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     */\n    @Override\n    public Object put(String key, Object value) {\n        return super.put((String)key, value);\n    }\n    \n    /**\n     * <p>\n     * Retrieve the identified <code>int</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not an Integer.\n     */\n    public int getInt(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Integer)\n                return (Integer) obj;\n            return Integer.parseInt((String)obj);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not an Integer.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>long</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a Long.\n     */\n    public long getLong(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Long)\n                return (Long) obj;\n            return Long.parseLong((String)obj);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a Long.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>float</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a Float.\n     */\n    public float getFloat(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Float)\n                return (Float) obj;\n            return Float.parseFloat((String)obj);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a Float.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>double</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a Double.\n     */\n    public double getDouble(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Double)\n                return (Double) obj;\n            return Double.parseDouble((String)obj);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a Double.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>boolean</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a Boolean.\n     */\n    public boolean getBoolean(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Boolean)\n                return (Boolean) obj;\n            return Boolean.parseBoolean((String)obj);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a Boolean.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>char</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a Character.\n     */\n    public char getChar(String key) {\n        Object obj = get(key);\n    \n        try {\n            if(obj instanceof Character)\n                return (Character) obj;\n            return ((String)obj).charAt(0);\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a Character.\");\n        }\n    }\n\n    /**\n     * <p>\n     * Retrieve the identified <code>String</code> value from the <code>StringKeyDirtyFlagMap</code>.\n     * </p>\n     * \n     * @throws ClassCastException\n     *           if the identified object is not a String.\n     */\n    public String getString(String key) {\n        Object obj = get(key);\n    \n        try {\n            return (String) obj;\n        } catch (Exception e) {\n            throw new ClassCastException(\"Identified object is not a String.\");\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/Counter.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter;\n\n/**\n * A simple counter\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * \n * @since 1.8\n */\npublic interface Counter {\n\n    /**\n     * Increment the counter by 1\n     * \n     * @return the value after incrementing\n     */\n    long increment();\n\n    /**\n     * Decrement the counter by 1\n     * \n     * @return the value after decrementing\n     */\n    long decrement();\n\n    /**\n     * Returns the value of the counter and sets it to the new value\n     * \n     * @param newValue\n     * @return Returns the old value\n     */\n    long getAndSet(long newValue);\n\n    /**\n     * Gets current value of the counter\n     * \n     * @return current value of the counter\n     */\n    long getValue();\n\n    /**\n     * Increment the counter by given amount\n     * \n     * @param amount\n     * @return the value of the counter after incrementing\n     */\n    long increment(long amount);\n\n    /**\n     * Decrement the counter by given amount\n     * \n     * @param amount\n     * @return the value of the counter after decrementing\n     */\n    long decrement(long amount);\n\n    /**\n     * Sets the value of the counter to the supplied value\n     * \n     * @param newValue\n     */\n    void setValue(long newValue);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/CounterConfig.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter;\n\n/**\n * Config for a simple Counter\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic class CounterConfig {\n\n    private final long initialValue;\n\n    /**\n     * Creates a config with the initial value\n     * \n     * @param initialValue\n     */\n    public CounterConfig(long initialValue) {\n        this.initialValue = initialValue;\n    }\n\n    /**\n     * Gets the initial value\n     * \n     * @return the initial value of counters created by this config\n     */\n    public final long getInitialValue() {\n        return initialValue;\n    }\n\n    /**\n     * Creates and returns a Counter based on the initial value\n     * \n     * @return The counter created by this config\n     */\n    public Counter createCounter() {\n        return new CounterImpl(initialValue);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/CounterImpl.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter;\n\nimport java.io.Serializable;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * A simple counter implementation\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic class CounterImpl implements Counter, Serializable {\n  \n    private static final long serialVersionUID = -1529134342654953984L;\n    \n    private final AtomicLong value;\n\n    /**\n     * Default Constructor\n     */\n    public CounterImpl() {\n        this(0L);\n    }\n\n    /**\n     * Constructor with initial value\n     * \n     * @param initialValue\n     */\n    public CounterImpl(long initialValue) {\n        this.value = new AtomicLong(initialValue);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long increment() {\n        return value.incrementAndGet();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long decrement() {\n        return value.decrementAndGet();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long getAndSet(long newValue) {\n        return value.getAndSet(newValue);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long getValue() {\n        return value.get();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long increment(long amount) {\n        return value.addAndGet(amount);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long decrement(long amount) {\n        return value.addAndGet(amount * -1);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void setValue(long newValue) {\n        value.set(newValue);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/CounterManager.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter;\n\n/**\n * A Counter Manager that accepts a config to create counters. Creates counter's\n * based on {@link CounterConfig}. This manages the lifecycle of a counter\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic interface CounterManager {\n    /**\n     * Creates a Counter based on tha passed config\n     * \n     * @param config\n     * @return The counter created and managed by this CounterManager\n     */\n    Counter createCounter(CounterConfig config);\n\n    /**\n     * Shuts down this counter manager\n     */\n    void shutdown(boolean killTimer);\n\n    /**\n     * Shuts down the counter\n     * \n     * @param counter\n     */\n    void shutdownCounter(Counter counter);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/CounterManagerImpl.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Timer;\n\nimport org.quartz.utils.counter.sampled.SampledCounter;\nimport org.quartz.utils.counter.sampled.SampledCounterImpl;\n\n/**\n * An implementation of a {@link CounterManager}.\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic class CounterManagerImpl implements CounterManager {\n\n    private final Timer timer;\n    private boolean shutdown;\n    private final List<Counter> counters = new ArrayList<>();\n\n    /**\n     * Constructor that accepts a timer that will be used for scheduling sampled\n     * counter if any is created\n     */\n    public CounterManagerImpl(Timer timer) {\n        if (timer == null) {\n            throw new IllegalArgumentException(\"Timer cannot be null\");\n        }\n        this.timer = timer;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void shutdown(boolean killTimer) {\n        if (shutdown) {\n            return;\n        }\n        try {\n            // shutdown the counters of this counterManager\n            for (Counter counter : counters) {\n                if (counter instanceof SampledCounter) {\n                    ((SampledCounter) counter).shutdown();\n                }\n            }\n            if(killTimer)\n                timer.cancel();\n        } finally {\n            shutdown = true;\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized Counter createCounter(CounterConfig config) {\n        if (shutdown) {\n            throw new IllegalStateException(\"counter manager is shutdown\");\n        }\n        if (config == null) {\n            throw new NullPointerException(\"config cannot be null\");\n        }\n        Counter counter = config.createCounter();\n        if (counter instanceof SampledCounterImpl) {\n            SampledCounterImpl sampledCounter = (SampledCounterImpl) counter;\n            timer.schedule(sampledCounter.getTimerTask(), sampledCounter.getIntervalMillis(), sampledCounter.getIntervalMillis());\n        }\n        counters.add(counter);\n        return counter;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void shutdownCounter(Counter counter) {\n        if (counter instanceof SampledCounter) {\n            SampledCounter sc = (SampledCounter) counter;\n            sc.shutdown();\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledCounter.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\nimport org.quartz.utils.counter.Counter;\n\n/**\n * Interface of a sampled counter -- a counter that keeps sampled values\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic interface SampledCounter extends Counter {\n    /**\n     * Shutdown this counter\n     */\n    void shutdown();\n\n    /**\n     * Returns the most recent sampled value\n     * \n     * @return Value of the most recent sampled value\n     */\n    TimeStampedCounterValue getMostRecentSample();\n\n    /**\n     * Returns all samples in history\n     * \n     * @return An array containing the TimeStampedCounterValue's\n     */\n    TimeStampedCounterValue[] getAllSampleValues();\n\n    /**\n     * Returns the current value of the counter and resets it to 0\n     * \n     * @return current value of the counter\n     */\n    long getAndReset();\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledCounterConfig.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\nimport org.quartz.utils.counter.Counter;\nimport org.quartz.utils.counter.CounterConfig;\n\n/**\n * Config for a {@link SampledCounter}\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.7\n * \n */\npublic class SampledCounterConfig extends CounterConfig {\n    private final int intervalSecs;\n    private final int historySize;\n    private final boolean isReset;\n\n    /**\n     * Make a new timed counter config (duh)\n     * \n     * @param intervalSecs\n     *            the interval (in seconds) between sampling\n     * @param historySize\n     *            number of counter samples that will be retained in memory\n     * @param isResetOnSample\n     *            true if the counter should be reset to 0 upon each sample\n     */\n    public SampledCounterConfig(int intervalSecs, int historySize, boolean isResetOnSample, long initialValue) {\n        super(initialValue);\n        if (intervalSecs < 1) {\n            throw new IllegalArgumentException(\"Interval (\" + intervalSecs + \") must be greater than or equal to 1\");\n        }\n        if (historySize < 1) {\n            throw new IllegalArgumentException(\"History size (\" + historySize + \") must be greater than or equal to 1\");\n        }\n\n        this.intervalSecs = intervalSecs;\n        this.historySize = historySize;\n        this.isReset = isResetOnSample;\n    }\n\n    /**\n     * Returns the history size\n     * \n     * @return The history size\n     */\n    public int getHistorySize() {\n        return historySize;\n    }\n\n    /**\n     * Returns the interval time (seconds)\n     * \n     * @return Interval of the sampling thread in seconds\n     */\n    public int getIntervalSecs() {\n        return intervalSecs;\n    }\n\n    /**\n     * Returns true if counters created from this config will reset on each\n     * sample\n     * \n     * @return true if values are reset to the initial value after each sample\n     */\n    public boolean isResetOnSample() {\n        return this.isReset;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Counter createCounter() {\n        return new SampledCounterImpl(this);\n    }\n}"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledCounterImpl.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\nimport java.util.TimerTask;\n\nimport org.quartz.utils.CircularLossyQueue;\nimport org.quartz.utils.counter.CounterImpl;\n\n/**\n * An implementation of {@link SampledCounter}\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.7\n * \n */\npublic class SampledCounterImpl extends CounterImpl implements SampledCounter {\n  \n    private static final long serialVersionUID = -3605369302464131521L;\n    \n    private static final int MILLIS_PER_SEC = 1000;\n\n    /**\n     * The history of this counter\n     */\n    protected final CircularLossyQueue<TimeStampedCounterValue> history;\n\n    /**\n     * Should the counter reset on each sample?\n     */\n    protected final boolean resetOnSample;\n    private final TimerTask samplerTask;\n    private final long intervalMillis;\n\n    /**\n     * Constructor accepting a {@link SampledCounterConfig}\n     * \n     * @param config\n     */\n    public SampledCounterImpl(SampledCounterConfig config) {\n        super(config.getInitialValue());\n\n        this.intervalMillis = config.getIntervalSecs() * MILLIS_PER_SEC;\n        this.history = new CircularLossyQueue<>(config.getHistorySize());\n        this.resetOnSample = config.isResetOnSample();\n\n        this.samplerTask = new TimerTask() {\n            @Override\n            public void run() {\n                recordSample();\n            }\n        };\n\n        recordSample();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public TimeStampedCounterValue getMostRecentSample() {\n        return this.history.peek();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public TimeStampedCounterValue[] getAllSampleValues() {\n        return this.history.toArray(new TimeStampedCounterValue[this.history.depth()]);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void shutdown() {\n        if (samplerTask != null) {\n            samplerTask.cancel();\n        }\n    }\n\n    /**\n     * Returns the timer task for this sampled counter\n     * \n     * @return the timer task for this sampled counter\n     */\n    public TimerTask getTimerTask() {\n        return this.samplerTask;\n    }\n\n    /**\n     * Returns the sampling thread interval in millis\n     * \n     * @return the sampling thread interval in millis\n     */\n    public long getIntervalMillis() {\n        return intervalMillis;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    void recordSample() {\n        final long sample;\n        if (resetOnSample) {\n            sample = getAndReset();\n        } else {\n            sample = getValue();\n        }\n\n        final long now = System.currentTimeMillis();\n        TimeStampedCounterValue timedSample = new TimeStampedCounterValue(now, sample);\n\n        history.push(timedSample);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public long getAndReset() {\n        return getAndSet(0L);\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledRateCounter.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\n/**\n * Interface of a sampled rate counter -- a counter that keeps sampled values of\n * rates\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic interface SampledRateCounter extends SampledCounter {\n\n    /**\n     * Increments the numerator and denominator by the passed values\n     * \n     * @param numerator\n     * @param denominator\n     */\n    void increment(long numerator, long denominator);\n\n    /**\n     * Decrements the numerator and denominator by the passed values\n     * \n     * @param numerator\n     * @param denominator\n     */\n    void decrement(long numerator, long denominator);\n\n    /**\n     * Sets the values of the numerator and denominator to the passed values\n     * \n     * @param numerator\n     * @param denominator\n     */\n    void setValue(long numerator, long denominator);\n\n    /**\n     * Sets the value of the numerator to the passed value\n     * \n     * @param newValue\n     */\n    void setNumeratorValue(long newValue);\n\n    /**\n     * Sets the value of the denominator to the passed value\n     * \n     * @param newValue\n     */\n    void setDenominatorValue(long newValue);\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledRateCounterConfig.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\nimport org.quartz.utils.counter.Counter;\n\n/**\n * An implementation of {@link SampledCounterConfig}\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic class SampledRateCounterConfig extends SampledCounterConfig {\n\n    private final long initialNumeratorValue;\n    private final long initialDenominatorValue;\n\n    /**\n     * Constructor accepting the interval time in seconds, history-size and\n     * whether counters should reset on each sample or not.\n     * Initial values of both numerator and denominator are zeroes\n     * \n     * @param intervalSecs\n     * @param historySize\n     * @param isResetOnSample\n     */\n    public SampledRateCounterConfig(int intervalSecs, int historySize, boolean isResetOnSample) {\n        this(intervalSecs, historySize, isResetOnSample, 0, 0);\n    }\n\n    /**\n     * Constructor accepting the interval time in seconds, history-size and\n     * whether counters should reset on each sample or not. Also the initial\n     * values for the numerator and the denominator\n     * \n     * @param intervalSecs\n     * @param historySize\n     * @param isResetOnSample\n     * @param initialNumeratorValue\n     * @param initialDenominatorValue\n     */\n    public SampledRateCounterConfig(int intervalSecs, int historySize, boolean isResetOnSample, long initialNumeratorValue,\n            long initialDenominatorValue) {\n        super(intervalSecs, historySize, isResetOnSample, 0);\n        this.initialNumeratorValue = initialNumeratorValue;\n        this.initialDenominatorValue = initialDenominatorValue;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Counter createCounter() {\n        SampledRateCounterImpl sampledRateCounter = new SampledRateCounterImpl(this);\n        sampledRateCounter.setValue(initialNumeratorValue, initialDenominatorValue);\n        return sampledRateCounter;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/SampledRateCounterImpl.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\n/**\n * An implementation of {@link SampledRateCounter}\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n * \n */\npublic class SampledRateCounterImpl extends SampledCounterImpl implements SampledRateCounter {\n  \n    private static final long serialVersionUID = 6531350452676920607L;\n\n    private static final String OPERATION_NOT_SUPPORTED_MSG = \"This operation is not supported. Use SampledCounter Or Counter instead\";\n\n    private long numeratorValue;\n    private long denominatorValue;\n\n    /**\n     * Constructor accepting the config\n     * \n     * @param config\n     */\n    public SampledRateCounterImpl(SampledRateCounterConfig config) {\n        super(config);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void setValue(long numerator, long denominator) {\n        this.numeratorValue = numerator;\n        this.denominatorValue = denominator;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void increment(long numerator, long denominator) {\n        this.numeratorValue += numerator;\n        this.denominatorValue += denominator;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void decrement(long numerator, long denominator) {\n        this.numeratorValue -= numerator;\n        this.denominatorValue -= denominator;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void setDenominatorValue(long newValue) {\n        this.denominatorValue = newValue;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public synchronized void setNumeratorValue(long newValue) {\n        this.numeratorValue = newValue;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public synchronized long getValue() {\n        return denominatorValue == 0 ? 0 : (numeratorValue / denominatorValue);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public synchronized long getAndReset() {\n        long prevVal = getValue();\n        setValue(0, 0);\n        return prevVal;\n    }\n\n    // ====== unsupported operations. These operations need multiple params for\n    // this class\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public long getAndSet(long newValue) {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public synchronized void setValue(long newValue) {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public long decrement() {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public long decrement(long amount) {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    public long getMaxValue() {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    public long getMinValue() {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public long increment() {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n    /**\n     * throws {@link UnsupportedOperationException}\n     */\n    @Override\n    public long increment(long amount) {\n        throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_MSG);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/counter/sampled/TimeStampedCounterValue.java",
    "content": "/**\n *  All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage org.quartz.utils.counter.sampled;\n\nimport java.io.Serializable;\n\n/**\n * A counter value at a particular time instance\n * \n * @author <a href=\"mailto:asanoujam@terracottatech.com\">Abhishek Sanoujam</a>\n * @since 1.8\n */\npublic class TimeStampedCounterValue implements Serializable {\n  \n    private static final long serialVersionUID = 1931111347823687672L;\n    \n    private final long counterValue;\n    private final long timestamp;\n\n    /**\n     * Constructor accepting the value of both timestamp and the counter value.\n     * \n     * @param timestamp\n     * @param value\n     */\n    public TimeStampedCounterValue(long timestamp, long value) {\n        this.timestamp = timestamp;\n        this.counterValue = value;\n    }\n\n    /**\n     * Get the counter value\n     * \n     * @return The counter value\n     */\n    public long getCounterValue() {\n        return this.counterValue;\n    }\n\n    /**\n     * Get value of the timestamp\n     * \n     * @return the timestamp associated with the current value\n     */\n    public long getTimestamp() {\n        return this.timestamp;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String toString() {\n        return \"value: \" + this.counterValue + \", timestamp: \" + this.timestamp;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/utils/weblogic/WeblogicConnectionProvider.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.utils.weblogic;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport org.quartz.utils.ConnectionProvider;\n\nimport weblogic.jdbc.jts.Driver;\n\n/**\n * <p>\n * Provides connections via Weblogic's JTS driver.\n * </p>\n * \n * @see org.quartz.utils.ConnectionProvider\n * @see org.quartz.utils.DBConnectionManager\n * \n * @author Mohammad Rezaei\n * @author James House\n */\n@SuppressWarnings(\"deprecation\")\npublic class WeblogicConnectionProvider implements ConnectionProvider {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private final String poolName;\n\n    private weblogic.jdbc.jts.Driver driver;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public WeblogicConnectionProvider(String poolName) {\n        this.poolName = poolName;\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public Connection getConnection() throws SQLException {\n        return driver.connect(\"jdbc:weblogic:jts:\" + poolName,\n                (java.util.Properties) null);\n    }\n\n    public void initialize() throws SQLException {\n        try {\n            driver = (Driver) weblogic.jdbc.jts.Driver.class.newInstance();\n        } catch (Exception e) {\n            throw new SQLException(\n                    \"Could not get weblogic pool connection with name '\"\n                            + poolName + \"': \" + e.getClass().getName() + \": \"\n                            + e.getMessage());\n        }\n    }\n    \n    public void shutdown() throws SQLException {\n        // do nothing\n    }    \n\n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/xml/ValidationException.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.xml;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\n\n/**\n * Reports JobSchedulingDataLoader validation exceptions.\n * \n * @author <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n */\npublic class ValidationException extends Exception {\n\n    private static final long serialVersionUID = -1697832087051681357L;\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    private Collection<Exception> validationExceptions = new ArrayList<>();\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Constructor for ValidationException.\n     */\n    public ValidationException() {\n        super();\n    }\n\n    /**\n     * Constructor for ValidationException.\n     * \n     * @param message\n     *          exception message.\n     */\n    public ValidationException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor for ValidationException.\n     * \n     * @param errors\n     *          collection of validation exceptions.\n     */\n    public ValidationException(Collection<Exception> errors) {\n        this();\n        this.validationExceptions = Collections\n                .unmodifiableCollection(validationExceptions);\n        initCause(errors.iterator().next());\n    }\n    \n\n    /**\n     * Constructor for ValidationException.\n     * \n     * @param message\n     *          exception message.\n     * @param errors\n     *          collection of validation exceptions.\n     */\n    public ValidationException(String message, Collection<Exception> errors) {\n        this(message);\n        this.validationExceptions = Collections\n                .unmodifiableCollection(validationExceptions);\n        initCause(errors.iterator().next());\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * Returns collection of errors.\n     * \n     * @return collection of errors.\n     */\n    public Collection<Exception> getValidationExceptions() {\n        return validationExceptions;\n    }\n\n    /**\n     * Returns the detail message string.\n     * \n     * @return the detail message string.\n     */\n    @Override\n    public String getMessage() {\n        if (getValidationExceptions().isEmpty()) { return super.getMessage(); }\n\n        StringBuilder messageBuilder = new StringBuilder();\n\n        boolean isFirst = true;\n\n        for (Exception e : getValidationExceptions()) {\n            if (!isFirst) {\n                messageBuilder.append('\\n');\n            }\n            isFirst = false;\n\n            messageBuilder.append(e.getMessage());\n        }\n\n        return messageBuilder.toString();\n    }\n    \n    \n}\n"
  },
  {
    "path": "quartz/src/main/java/org/quartz/xml/XMLSchedulingDataProcessor.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.xml;\n\nimport static org.quartz.CalendarIntervalScheduleBuilder.calendarIntervalSchedule;\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\nimport static org.quartz.TriggerKey.triggerKey;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimeZone;\n\nimport javax.xml.XMLConstants;\nimport javax.xml.namespace.NamespaceContext;\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathException;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.quartz.*;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.MutableTrigger;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.ErrorHandler;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport jakarta.xml.bind.DatatypeConverter;\n\n\n/**\n * Parses an XML file that declares Jobs and their schedules (Triggers), and processes the related data.\n * \n * The xml document must conform to the format defined in\n * \"job_scheduling_data_2_0.xsd\"\n * \n * The same instance can be used again and again, however a single instance is not thread-safe.\n * \n * @author James House\n * @author Past contributions from <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n * @author Past contributions from pl47ypus\n * \n * @since Quartz 1.8\n */\npublic class XMLSchedulingDataProcessor implements ErrorHandler {\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String QUARTZ_NS = \"http://www.quartz-scheduler.org/xml/JobSchedulingData\";\n\n    public static final String QUARTZ_SCHEMA_WEB_URL = \"http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\";\n    \n    public static final String QUARTZ_XSD_PATH_IN_JAR = \"org/quartz/xml/job_scheduling_data_2_0.xsd\";\n\n    public static final String QUARTZ_XML_DEFAULT_FILE_NAME = \"quartz_data.xml\";\n\n    public static final String QUARTZ_SYSTEM_ID_JAR_PREFIX = \"jar:\";\n    \n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Data members.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    // pre-processing commands\n    protected final List<String> jobGroupsToDelete = new LinkedList<>();\n    protected final List<String> triggerGroupsToDelete = new LinkedList<>();\n    protected final List<JobKey> jobsToDelete = new LinkedList<>();\n    protected final List<TriggerKey> triggersToDelete = new LinkedList<>();\n\n    // scheduling commands\n    protected final List<JobDetail> loadedJobs = new LinkedList<>();\n    protected final List<MutableTrigger> loadedTriggers = new LinkedList<>();\n    \n    // directives\n    private boolean overWriteExistingData = true;\n    private boolean ignoreDuplicates = false;\n\n    protected final Collection<Exception> validationExceptions = new ArrayList<>();\n\n    \n    protected final ClassLoadHelper classLoadHelper;\n    protected final List<String> jobGroupsToNeverDelete = new LinkedList<>();\n    protected final List<String> triggerGroupsToNeverDelete = new LinkedList<>();\n    \n    private DocumentBuilder docBuilder = null;\n    private XPath xpath = null;\n    \n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n     \n    /**\n     * Constructor for JobSchedulingDataLoader.\n     * \n     * @param clh               class-loader helper to share with digester.\n     * @throws ParserConfigurationException if the XML parser cannot be configured as needed. \n     */\n    public XMLSchedulingDataProcessor(ClassLoadHelper clh) throws ParserConfigurationException {\n        this.classLoadHelper = clh;\n        initDocumentParser();\n    }\n    \n    /**\n     * Initializes the XML parser.\n     * @throws ParserConfigurationException \n     */\n    protected void initDocumentParser() throws ParserConfigurationException  {\n\n        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();\n\n        docBuilderFactory.setNamespaceAware(true);\n        docBuilderFactory.setValidating(true);\n        \n        docBuilderFactory.setAttribute(\"http://java.sun.com/xml/jaxp/properties/schemaLanguage\", \"http://www.w3.org/2001/XMLSchema\");\n        \n        docBuilderFactory.setAttribute(\"http://java.sun.com/xml/jaxp/properties/schemaSource\", resolveSchemaSource());\n        \n        docBuilderFactory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n        docBuilderFactory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", false);\n        docBuilderFactory.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n        docBuilderFactory.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", false);\n        docBuilderFactory.setXIncludeAware(false);\n        docBuilderFactory.setExpandEntityReferences(false);\n\n        docBuilder = docBuilderFactory.newDocumentBuilder();\n        \n        docBuilder.setErrorHandler(this);\n        \n        NamespaceContext nsContext = new NamespaceContext()\n        {\n          public String getNamespaceURI(String prefix)\n          {\n              if (prefix == null)\n                  throw new IllegalArgumentException(\"Null prefix\");\n              switch (prefix) {\n                  case XMLConstants.XML_NS_PREFIX:\n                      return XMLConstants.XML_NS_URI;\n                  case XMLConstants.XMLNS_ATTRIBUTE:\n                      return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;\n                  case \"q\":\n                      return QUARTZ_NS;\n              }\n\n              return XMLConstants.NULL_NS_URI;\n          }\n        \n          public Iterator<String> getPrefixes(String namespaceURI)\n          {\n              // This method isn't necessary for XPath processing.\n              throw new UnsupportedOperationException();\n          }\n        \n          public String getPrefix(String namespaceURI)\n          {\n              // This method isn't necessary for XPath processing.\n              throw new UnsupportedOperationException();\n          }\n        \n        }; \n        \n        xpath = XPathFactory.newInstance().newXPath();\n        xpath.setNamespaceContext(nsContext);\n    }\n    \n    protected Object resolveSchemaSource() {\n        InputSource inputSource;\n\n        InputStream is = null;\n\n        try {\n            is = classLoadHelper.getResourceAsStream(QUARTZ_XSD_PATH_IN_JAR);\n        }  finally {\n            if (is != null) {\n                inputSource = new InputSource(is);\n                inputSource.setSystemId(QUARTZ_SCHEMA_WEB_URL);\n                log.debug(\"Utilizing schema packaged in local quartz distribution jar.\");\n            }\n            else {\n                log.info(\"Unable to load local schema packaged in quartz distribution jar. Utilizing schema online at \" + QUARTZ_SCHEMA_WEB_URL);\n                return QUARTZ_SCHEMA_WEB_URL;\n            }\n                \n        }\n\n        return inputSource;\n    }\n\n    /**\n     * Whether the existing scheduling data (with same identifiers) will be \n     * overwritten. \n     * \n     * If false, and <code>IgnoreDuplicates</code> is not false, and jobs or \n     * triggers with the same names already exist as those in the file, an \n     * error will occur.\n     * \n     * @see #isIgnoreDuplicates()\n     */\n    public boolean isOverWriteExistingData() {\n        return overWriteExistingData;\n    }\n    \n    /**\n     * Whether the existing scheduling data (with same identifiers) will be \n     * overwritten. \n     * \n     * If false, and <code>IgnoreDuplicates</code> is not false, and jobs or \n     * triggers with the same names already exist as those in the file, an \n     * error will occur.\n     * \n     * @see #setIgnoreDuplicates(boolean)\n     */\n    protected void setOverWriteExistingData(boolean overWriteExistingData) {\n        this.overWriteExistingData = overWriteExistingData;\n    }\n\n    /**\n     * If true (and <code>OverWriteExistingData</code> is false) then any \n     * job/triggers encountered in this file that have names that already exist \n     * in the scheduler will be ignored, and no error will be produced.\n     * \n     * @see #isOverWriteExistingData()\n     */ \n    public boolean isIgnoreDuplicates() {\n        return ignoreDuplicates;\n    }\n\n    /**\n     * If true (and <code>OverWriteExistingData</code> is false) then any \n     * job/triggers encountered in this file that have names that already exist \n     * in the scheduler will be ignored, and no error will be produced.\n     * \n     * @see #setOverWriteExistingData(boolean)\n     */ \n    public void setIgnoreDuplicates(boolean ignoreDuplicates) {\n        this.ignoreDuplicates = ignoreDuplicates;\n    }\n\n    /**\n     * Add the given group to the list of job groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public void addJobGroupToNeverDelete(String group) {\n        if(group != null)\n            jobGroupsToNeverDelete.add(group);\n    }\n    \n    /**\n     * Remove the given group to the list of job groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public boolean removeJobGroupToNeverDelete(String group) {\n        return group != null && jobGroupsToNeverDelete.remove(group);\n    }\n\n    /**\n     * Get the (unmodifiable) list of job groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public List<String> getJobGroupsToNeverDelete() {\n        return Collections.unmodifiableList(jobGroupsToDelete);\n    }\n\n    /**\n     * Add the given group to the list of trigger groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public void addTriggerGroupToNeverDelete(String group) {\n        if(group != null)\n            triggerGroupsToNeverDelete.add(group);\n    }\n    \n    /**\n     * Remove the given group to the list of trigger groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public boolean removeTriggerGroupToNeverDelete(String group) {\n        if(group != null)\n            return triggerGroupsToNeverDelete.remove(group);\n        return false;\n    }\n\n    /**\n     * Get the (unmodifiable) list of trigger groups that will never be\n     * deleted by this processor, even if a pre-processing-command to\n     * delete the group is encountered.\n     */\n    public List<String> getTriggerGroupsToNeverDelete() {\n        return Collections.unmodifiableList(triggerGroupsToDelete);\n    }\n    \n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n\n    /**\n     * Process the xml file in the default location (a file named\n     * \"quartz_jobs.xml\" in the current working directory).\n     *  \n     */\n    protected void processFile() throws Exception {\n        processFile(QUARTZ_XML_DEFAULT_FILE_NAME);\n    }\n\n    /**\n     * Process the xml file named <code>fileName</code>.\n     * \n     * @param fileName\n     *          meta data file name.\n     */\n    protected void processFile(String fileName) throws Exception {\n        processFile(fileName, getSystemIdForFileName(fileName));\n    }\n\n    /**\n     * For the given <code>fileName</code>, attempt to expand it to its full path\n     * for use as a system id.\n     * \n     * @see #getURL(String)\n     * @see #processFile()\n     * @see #processFile(String)\n     * @see #processFileAndScheduleJobs(Scheduler, boolean)\n     * @see #processFileAndScheduleJobs(String, org.quartz.Scheduler)\n     */\n    protected String getSystemIdForFileName(String fileName) {\n        File file = new File(fileName); // files in filesystem\n        if (file.exists()) {\n            try {\n                new FileInputStream(file).close();\n                return file.toURI().toString();\n            }catch (IOException ignore) {\n                return fileName;\n            }\n        } else {\n            URL url = getURL(fileName);\n            if (url == null) {\n                return fileName;\n            } else {\n                try {\n                    url.openStream().close();\n                    return url.toString();\n                } catch (IOException ignore) {\n                    return fileName;\n                }\n            }      \n        }\n    }\n\n    /**\n     * Returns an <code>URL</code> from the fileName as a resource.\n     * \n     * @param fileName\n     *          file name.\n     * @return an <code>URL</code> from the fileName as a resource.\n     */\n    protected URL getURL(String fileName) {\n        return classLoadHelper.getResource(fileName); \n    }\n\n    protected void prepForProcessing()\n    {\n        clearValidationExceptions();\n        \n        setOverWriteExistingData(true);\n        setIgnoreDuplicates(false);\n\n        jobGroupsToDelete.clear();\n        jobsToDelete.clear();\n        triggerGroupsToDelete.clear();\n        triggersToDelete.clear();\n        \n        loadedJobs.clear();\n        loadedTriggers.clear();\n    }\n    \n    /**\n     * Process the xmlfile named <code>fileName</code> with the given system\n     * ID.\n     * \n     * @param fileName\n     *          meta data file name.\n     * @param systemId\n     *          system ID.\n     */\n    protected void processFile(String fileName, String systemId)\n        throws ValidationException, ParserConfigurationException,\n            SAXException, IOException, SchedulerException,\n            ClassNotFoundException, ParseException, XPathException {\n\n        prepForProcessing();\n\n        log.info(\"Parsing XML file: {} with systemId: {}\", fileName, systemId);\n        InputSource is = new InputSource(getInputStream(fileName));\n        is.setSystemId(systemId);\n        \n        process(is);\n        \n        maybeThrowValidationException();\n    }\n    \n    /**\n     * Process the xmlfile named <code>fileName</code> with the given system\n     * ID.\n     * \n     * @param stream\n     *          an input stream containing the xml content.\n     * @param systemId\n     *          system ID.\n     */\n    public void processStreamAndScheduleJobs(InputStream stream, String systemId, Scheduler sched)\n        throws ValidationException, ParserConfigurationException,\n            SAXException, XPathException, IOException, SchedulerException,\n            ClassNotFoundException, ParseException {\n\n        prepForProcessing();\n\n        log.info(\"Parsing XML from stream with systemId: {}\", systemId);\n\n        InputSource is = new InputSource(stream);\n        is.setSystemId(systemId);\n\n        process(is);\n        executePreProcessCommands(sched);\n        scheduleJobs(sched);\n\n        maybeThrowValidationException();\n    }\n    \n    @SuppressWarnings(\"ConstantConditions\")\n    protected void process(InputSource is) throws SAXException, IOException, ParseException, XPathException, ClassNotFoundException {\n        \n        // load the document \n        Document document = docBuilder.parse(is);\n        \n        //\n        // Extract pre-processing commands\n        //\n\n        NodeList deleteJobGroupNodes = (NodeList) xpath.evaluate(\n                \"/q:job-scheduling-data/q:pre-processing-commands/q:delete-jobs-in-group\",\n                document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} delete job group commands.\", deleteJobGroupNodes.getLength());\n\n        for (int i = 0; i < deleteJobGroupNodes.getLength(); i++) {\n            Node node = deleteJobGroupNodes.item(i);\n            String t = node.getTextContent();\n            if(t == null || (t = t.trim()).isEmpty())\n                continue;\n            jobGroupsToDelete.add(t);\n        }\n\n        NodeList deleteTriggerGroupNodes = (NodeList) xpath.evaluate(\n                \"/q:job-scheduling-data/q:pre-processing-commands/q:delete-triggers-in-group\",\n                document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} delete trigger group commands.\", deleteTriggerGroupNodes.getLength());\n\n        for (int i = 0; i < deleteTriggerGroupNodes.getLength(); i++) {\n            Node node = deleteTriggerGroupNodes.item(i);\n            String t = node.getTextContent();\n            if(t == null || (t = t.trim()).isEmpty())\n                continue;\n            triggerGroupsToDelete.add(t);\n        }\n\n        NodeList deleteJobNodes = (NodeList) xpath.evaluate(\n                \"/q:job-scheduling-data/q:pre-processing-commands/q:delete-job\",\n                document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} delete job commands.\", deleteJobNodes.getLength());\n\n        for (int i = 0; i < deleteJobNodes.getLength(); i++) {\n            Node node = deleteJobNodes.item(i);\n\n            String name = getTrimmedToNullString(xpath, \"q:name\", node);\n            String group = getTrimmedToNullString(xpath, \"q:group\", node);\n            \n            if(name == null)\n                throw new ParseException(\"Encountered a 'delete-job' command without a name specified.\", -1);\n            jobsToDelete.add(new JobKey(name, group));\n        }\n\n        NodeList deleteTriggerNodes = (NodeList) xpath.evaluate(\n                \"/q:job-scheduling-data/q:pre-processing-commands/q:delete-trigger\",\n                document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} delete trigger commands.\", deleteTriggerNodes.getLength());\n\n        for (int i = 0; i < deleteTriggerNodes.getLength(); i++) {\n            Node node = deleteTriggerNodes.item(i);\n\n            String name = getTrimmedToNullString(xpath, \"q:name\", node);\n            String group = getTrimmedToNullString(xpath, \"q:group\", node);\n            \n            if(name == null)\n                throw new ParseException(\"Encountered a 'delete-trigger' command without a name specified.\", -1);\n            triggersToDelete.add(new TriggerKey(name, group));\n        }\n        \n        //\n        // Extract directives\n        //\n\n        Boolean overWrite = getBoolean(xpath, \n                \"/q:job-scheduling-data/q:processing-directives/q:overwrite-existing-data\", document);\n        if(overWrite == null) {\n            log.debug(\"Directive 'overwrite-existing-data' not specified, defaulting to {}\", isOverWriteExistingData());\n        }\n        else {\n            log.debug(\"Directive 'overwrite-existing-data' specified as: {}\", overWrite);\n            setOverWriteExistingData(overWrite);\n        }\n        \n        Boolean ignoreDupes = getBoolean(xpath, \n                \"/q:job-scheduling-data/q:processing-directives/q:ignore-duplicates\", document);\n        if(ignoreDupes == null) {\n            log.debug(\"Directive 'ignore-duplicates' not specified, defaulting to {}\", isIgnoreDuplicates());\n        }\n        else {\n            log.debug(\"Directive 'ignore-duplicates' specified as: {}\", ignoreDupes);\n            setIgnoreDuplicates(ignoreDupes);\n        }\n        \n        //\n        // Extract Job definitions...\n        //\n\n        NodeList jobNodes = (NodeList) xpath.evaluate(\"/q:job-scheduling-data/q:schedule/q:job\",\n                document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} job definitions.\", jobNodes.getLength());\n\n        for (int i = 0; i < jobNodes.getLength(); i++) {\n            Node jobDetailNode = jobNodes.item(i);\n            String t;\n\n            String jobName = getTrimmedToNullString(xpath, \"q:name\", jobDetailNode);\n            String jobGroup = getTrimmedToNullString(xpath, \"q:group\", jobDetailNode);\n            String jobDescription = getTrimmedToNullString(xpath, \"q:description\", jobDetailNode);\n            String jobClassName = getTrimmedToNullString(xpath, \"q:job-class\", jobDetailNode);\n            t = getTrimmedToNullString(xpath, \"q:durability\", jobDetailNode);\n            boolean jobDurability = (t != null) && t.equals(\"true\");\n            t = getTrimmedToNullString(xpath, \"q:recover\", jobDetailNode);\n            boolean jobRecoveryRequested = (t != null) && t.equals(\"true\");\n\n            Class<? extends Job> jobClass = classLoadHelper.loadClass(jobClassName, Job.class);\n\n            JobDetail jobDetail = newJob(jobClass)\n                .withIdentity(jobName, jobGroup)\n                .withDescription(jobDescription)\n                .storeDurably(jobDurability)\n                .requestRecovery(jobRecoveryRequested)\n                .build();\n            \n            NodeList jobDataEntries = (NodeList) xpath.evaluate(\n                    \"q:job-data-map/q:entry\", jobDetailNode,\n                    XPathConstants.NODESET);\n            \n            for (int k = 0; k < jobDataEntries.getLength(); k++) {\n                Node entryNode = jobDataEntries.item(k);\n                String key = getTrimmedToNullString(xpath, \"q:key\", entryNode);\n                String value = getTrimmedToNullString(xpath, \"q:value\", entryNode);\n                jobDetail.getJobDataMap().put(key, value);\n            }\n            \n            if(log.isDebugEnabled())\n                log.debug(\"Parsed job definition: {}\", jobDetail);\n\n            addJobToSchedule(jobDetail);\n        }\n        \n        //\n        // Extract Trigger definitions...\n        //\n\n        NodeList triggerEntries = (NodeList) xpath.evaluate(\n                \"/q:job-scheduling-data/q:schedule/q:trigger/*\", document, XPathConstants.NODESET);\n\n        log.debug(\"Found {} trigger definitions.\", triggerEntries.getLength());\n\n        for (int j = 0; j < triggerEntries.getLength(); j++) {\n            Node triggerNode = triggerEntries.item(j);\n            String triggerName = getTrimmedToNullString(xpath, \"q:name\", triggerNode);\n            String triggerGroup = getTrimmedToNullString(xpath, \"q:group\", triggerNode);\n            String triggerDescription = getTrimmedToNullString(xpath, \"q:description\", triggerNode);\n            String triggerMisfireInstructionConst = getTrimmedToNullString(xpath, \"q:misfire-instruction\", triggerNode);\n            String triggerPriorityString = getTrimmedToNullString(xpath, \"q:priority\", triggerNode);\n            String triggerCalendarRef = getTrimmedToNullString(xpath, \"q:calendar-name\", triggerNode);\n            String triggerJobName = getTrimmedToNullString(xpath, \"q:job-name\", triggerNode);\n            String triggerJobGroup = getTrimmedToNullString(xpath, \"q:job-group\", triggerNode);\n\n            int triggerPriority = Trigger.DEFAULT_PRIORITY;\n            if(triggerPriorityString != null)\n                triggerPriority = Integer.valueOf(triggerPriorityString);\n            \n            String startTimeString = getTrimmedToNullString(xpath, \"q:start-time\", triggerNode);\n            String startTimeFutureSecsString = getTrimmedToNullString(xpath, \"q:start-time-seconds-in-future\", triggerNode);\n            String endTimeString = getTrimmedToNullString(xpath, \"q:end-time\", triggerNode);\n\n            //QTZ-273 : use of DatatypeConverter.parseDateTime() instead of SimpleDateFormat\n            Date triggerStartTime;\n            if(startTimeFutureSecsString != null)\n                triggerStartTime = new Date(System.currentTimeMillis() + (Long.valueOf(startTimeFutureSecsString) * 1000L));\n            else \n                triggerStartTime = (startTimeString == null || startTimeString.isEmpty() ? new Date() : DatatypeConverter.parseDateTime(startTimeString).getTime());\n            Date triggerEndTime = endTimeString == null || endTimeString.isEmpty() ? null : DatatypeConverter.parseDateTime(endTimeString).getTime();\n\n            TriggerKey triggerKey = triggerKey(triggerName, triggerGroup);\n            \n            ScheduleBuilder<?> sched;\n\n            switch (triggerNode.getNodeName()) {\n                case \"simple\": {\n                    String repeatCountString = getTrimmedToNullString(xpath, \"q:repeat-count\", triggerNode);\n                    String repeatIntervalString = getTrimmedToNullString(xpath, \"q:repeat-interval\", triggerNode);\n\n                    int repeatCount = repeatCountString == null ? 0 : Integer.parseInt(repeatCountString);\n                    long repeatInterval = repeatIntervalString == null ? 0 : Long.parseLong(repeatIntervalString);\n\n                    sched = simpleSchedule()\n                            .withIntervalInMilliseconds(repeatInterval)\n                            .withRepeatCount(repeatCount);\n\n                    if (triggerMisfireInstructionConst != null && !triggerMisfireInstructionConst.isEmpty()) {\n                        switch (triggerMisfireInstructionConst) {\n                            case \"MISFIRE_INSTRUCTION_FIRE_NOW\":\n                                ((SimpleScheduleBuilder) sched).withMisfireHandlingInstructionFireNow();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT\":\n                                ((SimpleScheduleBuilder) sched).withMisfireHandlingInstructionNextWithExistingCount();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT\":\n                                ((SimpleScheduleBuilder) sched).withMisfireHandlingInstructionNextWithRemainingCount();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT\":\n                                ((SimpleScheduleBuilder) sched).withMisfireHandlingInstructionNowWithExistingCount();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT\":\n                                ((SimpleScheduleBuilder) sched).withMisfireHandlingInstructionNowWithRemainingCount();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_SMART_POLICY\":\n                                // do nothing.... (smart policy is default)\n                                break;\n                            default:\n                                throw new ParseException(\"Unexpected/Unhandleable Misfire Instruction encountered '\" + triggerMisfireInstructionConst + \"', for trigger: \" + triggerKey, -1);\n                        }\n                    }\n                    break;\n                }\n                case \"cron\":\n                    String cronExpression = getTrimmedToNullString(xpath, \"q:cron-expression\", triggerNode);\n                    String timezoneString = getTrimmedToNullString(xpath, \"q:time-zone\", triggerNode);\n\n                    TimeZone tz = timezoneString == null ? null : TimeZone.getTimeZone(timezoneString);\n\n                    sched = cronSchedule(cronExpression)\n                            .inTimeZone(tz);\n\n                    if (triggerMisfireInstructionConst != null && !triggerMisfireInstructionConst.isEmpty()) {\n                        switch (triggerMisfireInstructionConst) {\n                            case \"MISFIRE_INSTRUCTION_DO_NOTHING\":\n                                ((CronScheduleBuilder) sched).withMisfireHandlingInstructionDoNothing();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\":\n                                ((CronScheduleBuilder) sched).withMisfireHandlingInstructionFireAndProceed();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_SMART_POLICY\":\n                                // do nothing.... (smart policy is default)\n                                break;\n                            default:\n                                throw new ParseException(\"Unexpected/Unhandleable Misfire Instruction encountered '\" + triggerMisfireInstructionConst + \"', for trigger: \" + triggerKey, -1);\n                        }\n                    }\n                    break;\n                case \"calendar-interval\": {\n                    String repeatIntervalString = getTrimmedToNullString(xpath, \"q:repeat-interval\", triggerNode);\n                    String repeatUnitString = getTrimmedToNullString(xpath, \"q:repeat-interval-unit\", triggerNode);\n\n                    int repeatInterval = Integer.parseInt(repeatIntervalString);\n\n                    IntervalUnit repeatUnit = IntervalUnit.valueOf(repeatUnitString);\n\n                    sched = calendarIntervalSchedule()\n                            .withInterval(repeatInterval, repeatUnit);\n\n                    if (triggerMisfireInstructionConst != null && !triggerMisfireInstructionConst.isEmpty()) {\n                        switch (triggerMisfireInstructionConst) {\n                            case \"MISFIRE_INSTRUCTION_DO_NOTHING\":\n                                ((CalendarIntervalScheduleBuilder) sched).withMisfireHandlingInstructionDoNothing();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\":\n                                ((CalendarIntervalScheduleBuilder) sched).withMisfireHandlingInstructionFireAndProceed();\n                                break;\n                            case \"MISFIRE_INSTRUCTION_SMART_POLICY\":\n                                // do nothing.... (smart policy is default)\n                                break;\n                            default:\n                                throw new ParseException(\"Unexpected/Unhandleable Misfire Instruction encountered '\" + triggerMisfireInstructionConst + \"', for trigger: \" + triggerKey, -1);\n                        }\n                    }\n                    break;\n                }\n                default:\n                    throw new ParseException(\"Unknown trigger type: \" + triggerNode.getNodeName(), -1);\n            }\n\n            \n            MutableTrigger trigger = (MutableTrigger) newTrigger()\n                .withIdentity(triggerName, triggerGroup)\n                .withDescription(triggerDescription)\n                .forJob(triggerJobName, triggerJobGroup)\n                .startAt(triggerStartTime)\n                .endAt(triggerEndTime)\n                .withPriority(triggerPriority)\n                .modifiedByCalendar(triggerCalendarRef)\n                .withSchedule(sched)\n                .build();\n\n            NodeList jobDataEntries = (NodeList) xpath.evaluate(\n                    \"q:job-data-map/q:entry\", triggerNode,\n                    XPathConstants.NODESET);\n            \n            for (int k = 0; k < jobDataEntries.getLength(); k++) {\n                Node entryNode = jobDataEntries.item(k);\n                String key = getTrimmedToNullString(xpath, \"q:key\", entryNode);\n                String value = getTrimmedToNullString(xpath, \"q:value\", entryNode);\n                trigger.getJobDataMap().put(key, value);\n            }\n            \n            if(log.isDebugEnabled())\n                log.debug(\"Parsed trigger definition: {}\", trigger);\n            \n            addTriggerToSchedule(trigger);\n        }\n    }\n    \n    protected String getTrimmedToNullString(XPath xpathToElement, String elementName, Node parentNode) throws XPathExpressionException {\n        String str = (String) xpathToElement.evaluate(elementName,\n                parentNode, XPathConstants.STRING);\n        \n        if(str != null)\n            str = str.trim();\n        \n        if(str != null && str.isEmpty())\n            str = null;\n        \n        return str;\n    }\n\n    protected Boolean getBoolean(XPath xpathToElement, String elementName, Document document) throws XPathExpressionException {\n        \n        Node directive = (Node) xpathToElement.evaluate(elementName, document, XPathConstants.NODE);\n\n        if(directive == null || directive.getTextContent() == null)\n            return null;\n        \n        String val = directive.getTextContent();\n        if(val.equalsIgnoreCase(\"true\") || val.equalsIgnoreCase(\"yes\") || val.equalsIgnoreCase(\"y\"))\n            return Boolean.TRUE;\n        \n        return Boolean.FALSE;\n    }\n\n    /**\n     * Process the xml file in the default location, and schedule all of the\n     * jobs defined within it.\n     * \n     * <p>Note that we will set overWriteExistingJobs after the default xml is parsed. \n     */\n    public void processFileAndScheduleJobs(Scheduler sched,\n            boolean overWriteExistingJobs) throws Exception {\n        String fileName = QUARTZ_XML_DEFAULT_FILE_NAME;\n        processFile(fileName, getSystemIdForFileName(fileName));\n        // The overWriteExistingJobs flag was set by processFile() -> prepForProcessing(), then by xml parsing, and then now\n        // we need to reset it again here by this method parameter to override it.\n        setOverWriteExistingData(overWriteExistingJobs);\n        executePreProcessCommands(sched);\n        scheduleJobs(sched);\n    }\n\n    /**\n     * Process the xml file in the given location, and schedule all of the\n     * jobs defined within it.\n     * \n     * @param fileName\n     *          meta data file name.\n     */\n    public void processFileAndScheduleJobs(String fileName, Scheduler sched) throws Exception {\n        processFileAndScheduleJobs(fileName, getSystemIdForFileName(fileName), sched);\n    }\n    \n    /**\n     * Process the xml file in the given location, and schedule all of the\n     * jobs defined within it.\n     * \n     * @param fileName\n     *          meta data file name.\n     */\n    public void processFileAndScheduleJobs(String fileName, String systemId, Scheduler sched) throws Exception {\n        processFile(fileName, systemId);\n        executePreProcessCommands(sched);\n        scheduleJobs(sched);\n    }\n\n    /**\n     * Returns a <code>List</code> of jobs loaded from the xml file.\n     * \n     * @return a <code>List</code> of jobs.\n     */\n    protected List<JobDetail> getLoadedJobs() {\n        return Collections.unmodifiableList(loadedJobs);\n    }\n    \n    /**\n     * Returns a <code>List</code> of triggers loaded from the xml file.\n     * \n     * @return a <code>List</code> of triggers.\n     */\n    protected List<MutableTrigger> getLoadedTriggers() {\n        return Collections.unmodifiableList(loadedTriggers);\n    }\n\n    /**\n     * Returns an <code>InputStream</code> from the fileName as a resource.\n     * \n     * @param fileName\n     *          file name.\n     * @return an <code>InputStream</code> from the fileName as a resource.\n     */\n    protected InputStream getInputStream(String fileName) {\n        return this.classLoadHelper.getResourceAsStream(fileName);\n    }\n    \n    protected void addJobToSchedule(JobDetail job) {\n        loadedJobs.add(job);\n    }\n    \n    protected void addTriggerToSchedule(MutableTrigger trigger) {\n        loadedTriggers.add(trigger);\n    }\n\n    private Map<JobKey, List<MutableTrigger>> buildTriggersByFQJobNameMap(List<MutableTrigger> triggers) {\n        \n        Map<JobKey, List<MutableTrigger>> triggersByFQJobName = new HashMap<>();\n        \n        for(MutableTrigger trigger: triggers) {\n            List<MutableTrigger> triggersOfJob = triggersByFQJobName.computeIfAbsent(trigger.getJobKey(), k -> new LinkedList<>());\n            triggersOfJob.add(trigger);\n        }\n\n        return triggersByFQJobName;\n    }\n    \n    protected void executePreProcessCommands(Scheduler scheduler) \n        throws SchedulerException {\n        \n        for(String group: jobGroupsToDelete) {\n            if(group.equals(\"*\")) {\n                log.info(\"Deleting all jobs in ALL groups.\");\n                for (String groupName : scheduler.getJobGroupNames()) {\n                    if (!jobGroupsToNeverDelete.contains(groupName)) {\n                        for (JobKey key : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {\n                            scheduler.deleteJob(key);\n                        }\n                    }\n                }\n            }\n            else {\n                if(!jobGroupsToNeverDelete.contains(group)) {\n                    log.info(\"Deleting all jobs in group: {}\", group);\n                    for (JobKey key : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) {\n                        scheduler.deleteJob(key);\n                    }\n                }\n            }\n        }\n        \n        for(String group: triggerGroupsToDelete) {\n            if(group.equals(\"*\")) {\n                log.info(\"Deleting all triggers in ALL groups.\");\n                for (String groupName : scheduler.getTriggerGroupNames()) {\n                    if (!triggerGroupsToNeverDelete.contains(groupName)) {\n                        for (TriggerKey key : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName))) {\n                            scheduler.unscheduleJob(key);\n                        }\n                    }\n                }\n            }\n            else {\n                if(!triggerGroupsToNeverDelete.contains(group)) {\n                    log.info(\"Deleting all triggers in group: {}\", group);\n                    for (TriggerKey key : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(group))) {\n                        scheduler.unscheduleJob(key);\n                    }\n                }\n            }\n        }\n        \n        for(JobKey key: jobsToDelete) {\n            if(!jobGroupsToNeverDelete.contains(key.getGroup())) {\n                log.info(\"Deleting job: {}\", key);\n                scheduler.deleteJob(key);\n            } \n        }\n        \n        for(TriggerKey key: triggersToDelete) {\n            if(!triggerGroupsToNeverDelete.contains(key.getGroup())) {\n                log.info(\"Deleting trigger: {}\", key);\n                scheduler.unscheduleJob(key);\n            }\n        }\n    }\n\n    /**\n     * Schedules the given sets of jobs and triggers.\n     * \n     * @param sched\n     *          job scheduler.\n     * @exception SchedulerException\n     *              if the Job or Trigger cannot be added to the Scheduler, or\n     *              there is an internal Scheduler error.\n     */\n    @SuppressWarnings(\"ConstantConditions\")\n    protected void scheduleJobs(Scheduler sched)\n        throws SchedulerException {\n        \n        List<JobDetail> jobs = new LinkedList<>(getLoadedJobs());\n        List<MutableTrigger> triggers = new LinkedList<>(getLoadedTriggers());\n\n        log.info(\"Adding {} jobs, {} triggers.\", jobs.size(), triggers.size());\n        \n        Map<JobKey, List<MutableTrigger>> triggersByFQJobName = buildTriggersByFQJobNameMap(triggers);\n        \n        // add each job, and it's associated triggers\n        Iterator<JobDetail> itr = jobs.iterator();\n        while(itr.hasNext()) {\n            JobDetail detail = itr.next();\n            itr.remove(); // remove jobs as we handle them...\n\n            JobDetail dupeJ = null;\n            try {\n                // The existing job could have been deleted, and Quartz API doesn't allow us to query this without\n                // loading the job class, so use try/catch to handle it.\n                dupeJ = sched.getJobDetail(detail.getKey());\n            } catch (JobPersistenceException e) {\n                if (e.getCause() instanceof ClassNotFoundException && isOverWriteExistingData()) {\n                    // We are going to replace jobDetail anyway, so just delete it first.\n                    log.info(\"Removing job: {}\", detail.getKey());\n                    sched.deleteJob(detail.getKey());\n                } else {\n                    throw e;\n                }\n            }\n\n            if ((dupeJ != null)) {\n                if(!isOverWriteExistingData() && isIgnoreDuplicates()) {\n                    log.info(\"Not overwriting existing job: {}\", dupeJ.getKey());\n                    continue; // just ignore the entry\n                }\n                if(!isOverWriteExistingData() && !isIgnoreDuplicates()) {\n                    throw new ObjectAlreadyExistsException(detail);\n                }\n            }\n            \n            if (dupeJ != null) {\n                log.info(\"Replacing job: {}\", detail.getKey());\n            } else {\n                log.info(\"Adding job: {}\", detail.getKey());\n            }\n            \n            List<MutableTrigger> triggersOfJob = triggersByFQJobName.get(detail.getKey());\n            \n            if (!detail.isDurable() && (triggersOfJob == null || triggersOfJob.isEmpty())) {\n                if (dupeJ == null) {\n                    throw new SchedulerException(\n                        \"A new job defined without any triggers must be durable: \" + \n                        detail.getKey());\n                }\n                \n                if ((dupeJ.isDurable() && \n                    (sched.getTriggersOfJob(\n                            detail.getKey()).isEmpty()))) {\n                    throw new SchedulerException(\n                        \"Can't change existing durable job without triggers to non-durable: \" + \n                        detail.getKey());\n                }\n            }\n            \n            \n            if(dupeJ != null || detail.isDurable()) {\n                // add the job only if a replacement or durable, else exception will throw!\n                sched.addJob(detail, true, triggersOfJob != null && !triggersOfJob.isEmpty());  // add the job regardless is durable or not b/c we have trigger to add\n            }\n            else {\n                boolean addJobWithFirstSchedule = true;\n\n                // Add triggers related to the job...\n                for (MutableTrigger trigger : triggersOfJob) {\n                    triggers.remove(trigger);  // remove triggers as we handle them...\n\n                    if (trigger.getStartTime() == null) {\n                        trigger.setStartTime(new Date());\n                    }\n\n                    Trigger dupeT = sched.getTrigger(trigger.getKey());\n                    if (dupeT != null) {\n                        if (isOverWriteExistingData()) {\n                            if (log.isDebugEnabled()) {\n                                log.debug(\"Rescheduling job: {} with updated trigger: {}\", trigger.getJobKey(), trigger.getKey());\n                            }\n                        } else if (isIgnoreDuplicates()) {\n                            log.info(\"Not overwriting existing trigger: {}\", dupeT.getKey());\n                            continue; // just ignore the trigger (and possibly job)\n                        } else {\n                            throw new ObjectAlreadyExistsException(trigger);\n                        }\n\n                        if (!dupeT.getJobKey().equals(trigger.getJobKey())) {\n                            log.warn(\"Possibly duplicately named ({}) triggers in jobs xml file! \", trigger.getKey());\n                        }\n\n                        sched.rescheduleJob(trigger.getKey(), trigger);\n                    } else {\n                        if (log.isDebugEnabled()) {\n                            log.debug(\"Scheduling job: {} with trigger: {}\", trigger.getJobKey(), trigger.getKey());\n                        }\n\n                        try {\n                            if (addJobWithFirstSchedule) {\n                                sched.scheduleJob(detail, trigger); // add the job if it's not in yet...\n                                addJobWithFirstSchedule = false;\n                            } else {\n                                sched.scheduleJob(trigger);\n                            }\n                        } catch (ObjectAlreadyExistsException e) {\n                            if (log.isDebugEnabled()) {\n                                log.debug(\"Adding trigger: {} for job: {} 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.\", trigger.getKey(), detail.getKey());\n                            }\n\n                            // Let's try one more time as reschedule.\n                            sched.rescheduleJob(trigger.getKey(), trigger);\n                        }\n                    }\n                }\n            }\n        }\n        \n        // add triggers that weren't associated with a new job... (those we already handled were removed above)\n        for(MutableTrigger trigger: triggers) {\n            \n            if(trigger.getStartTime() == null) {\n                trigger.setStartTime(new Date());\n            }\n            \n            Trigger dupeT = sched.getTrigger(trigger.getKey());\n            if (dupeT != null) {\n                if(isOverWriteExistingData()) {\n                    if (log.isDebugEnabled()) {\n                        log.debug(\"Rescheduling job: {} with updated trigger: {}\", trigger.getJobKey(), trigger.getKey());\n                    }\n                }\n                else if(isIgnoreDuplicates()) {\n                    log.info(\"Not overwriting existing trigger: {}\", dupeT.getKey());\n                    continue; // just ignore the trigger \n                }\n                else {\n                    throw new ObjectAlreadyExistsException(trigger);\n                }\n                \n                if(!dupeT.getJobKey().equals(trigger.getJobKey())) {\n                    log.warn(\"Possibly duplicately named ({}) triggers in jobs xml file! \", trigger.getKey());\n                }\n                \n                sched.rescheduleJob(trigger.getKey(), trigger);\n            } else {\n                if (log.isDebugEnabled()) {\n                    log.debug(\"Scheduling job: {} with trigger: {}\", trigger.getJobKey(), trigger.getKey());\n                }\n\n                try {\n                    sched.scheduleJob(trigger);\n                } catch (ObjectAlreadyExistsException e) {\n                    if (log.isDebugEnabled()) {\n                        log.debug(\"Adding trigger: {} for job: {} 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.\", trigger.getKey(), trigger.getJobKey());\n                    }\n\n                    // Let's rescheduleJob one more time.\n                    sched.rescheduleJob(trigger.getKey(), trigger);\n                }\n            }\n        }\n    }\n\n    /**\n     * ErrorHandler interface.\n     * \n     * Receive notification of a warning.\n     * \n     * @param e\n     *          The error information encapsulated in a SAX parse exception.\n     * @exception SAXException\n     *              Any SAX exception, possibly wrapping another exception.\n     */\n    public void warning(SAXParseException e) throws SAXException {\n        addValidationException(e);\n    }\n\n    /**\n     * ErrorHandler interface.\n     * \n     * Receive notification of a recoverable error.\n     * \n     * @param e\n     *          The error information encapsulated in a SAX parse exception.\n     * @exception SAXException\n     *              Any SAX exception, possibly wrapping another exception.\n     */\n    public void error(SAXParseException e) throws SAXException {\n        addValidationException(e);\n    }\n\n    /**\n     * ErrorHandler interface.\n     * \n     * Receive notification of a non-recoverable error.\n     * \n     * @param e\n     *          The error information encapsulated in a SAX parse exception.\n     * @exception SAXException\n     *              Any SAX exception, possibly wrapping another exception.\n     */\n    public void fatalError(SAXParseException e) throws SAXException {\n        addValidationException(e);\n    }\n\n    /**\n     * Adds a detected validation exception.\n     * \n     * @param e\n     *          SAX exception.\n     */\n    protected void addValidationException(SAXException e) {\n        validationExceptions.add(e);\n    }\n\n    /**\n     * Resets the number of detected validation exceptions.\n     */\n    protected void clearValidationExceptions() {\n        validationExceptions.clear();\n    }\n\n    /**\n     * Throws a ValidationException if the number of validationExceptions\n     * detected is greater than zero.\n     * \n     * @exception ValidationException\n     *              DTD validation exception.\n     */\n    protected void maybeThrowValidationException() throws ValidationException {\n        if (!validationExceptions.isEmpty()) {\n            throw new ValidationException(\"Encountered \" + validationExceptions.size() + \" validation exceptions.\", validationExceptions);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/main/java/overview.html",
    "content": "<body>\n\nThis document is the API specification for Quartz.\n\n</body>\n"
  },
  {
    "path": "quartz/src/main/resources/checkstyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!DOCTYPE module PUBLIC\n    \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n    \"http://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n\n<module name=\"Checker\">\n  <property name=\"severity\" value=\"error\" />\n\n  <!--module name=\"Header\">\n    <property name=\"headerFile\" value=\"${checkstyle.header.file}\" />\n    <message key=\"header.missing\" value=\"Source file missing Quartz license header\" />\n    <message key=\"header.mismatch\" value=\"Quartz license header mismatch\" />\n  </module-->\n\n  <module name=\"FileTabCharacter\" />\n\n  <module name=\"TreeWalker\">\n    <module name=\"FileContentsHolder\"/>   \n  </module>\n  \n  <module name=\"SuppressionCommentFilter\">\n      <property name=\"offCommentFormat\" value=\"CHECKSTYLE_OFF\\: ([\\w\\|]+)\"/>\n      <property name=\"onCommentFormat\" value=\"CHECKSTYLE_ON\\: ([\\w\\|]+)\"/>\n      <property name=\"checkFormat\" value=\"$1\"/>\n  </module>\n</module>\n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/core/quartz-build.properties",
    "content": "fullname=$fullname\nname=$name\nversion=$version\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/liquibase.quartz.init.xml",
    "content": "<databaseChangeLog\n  xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\"\n  xsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd\n    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd\">\n\n    <property name=\"table_prefix\" value=\"QRTZ_\"/>\n\n    <property name=\"blob_type\" value=\"BYTEA\" dbms=\"postgresql\"/>\n    <property name=\"blob_type\" value=\"BLOB\"/>\n\n    <changeSet id=\"quartz-init\" author=\"quartz\">\n\n        <createTable tableName=\"${table_prefix}LOCKS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"LOCK_NAME\" type=\"VARCHAR(40)\">\n                <constraints nullable=\"false\"/>\n            </column>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, LOCK_NAME\" tableName=\"${table_prefix}LOCKS\"/>\n\n        <createTable tableName=\"${table_prefix}FIRED_TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"ENTRY_ID\" type=\"VARCHAR(95)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"INSTANCE_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"FIRED_TIME\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"SCHED_TIME\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"PRIORITY\" type=\"INTEGER\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"STATE\" type=\"VARCHAR(16)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_NAME\" type=\"VARCHAR(200)\"/>\n            <column name=\"JOB_GROUP\" type=\"VARCHAR(200)\"/>\n            <column name=\"IS_NONCONCURRENT\" type=\"BOOLEAN\"/>\n            <column name=\"REQUESTS_RECOVERY\" type=\"BOOLEAN\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, ENTRY_ID\" tableName=\"${table_prefix}FIRED_TRIGGERS\"/>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_INST_JOB_REQ_RCVRY\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"INSTANCE_NAME\"/>\n            <column name=\"REQUESTS_RECOVERY\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_J_G\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"JOB_NAME\"/>\n            <column name=\"JOB_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_JG\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"JOB_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_T_G\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_NAME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_TG\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}FIRED_TRIGGERS\" indexName=\"IDX_${table_prefix}FT_TRIG_INST_NAME\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"INSTANCE_NAME\"/>\n        </createIndex>\n\n        <createTable tableName=\"${table_prefix}CALENDARS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"CALENDAR_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"CALENDAR\" type=\"${blob_type}\">\n                <constraints nullable=\"false\"/>\n            </column>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, CALENDAR_NAME\" tableName=\"${table_prefix}CALENDARS\"/>\n\n        <createTable tableName=\"${table_prefix}PAUSED_TRIGGER_GRPS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}PAUSED_TRIGGER_GRPS\"/>\n\n        <createTable tableName=\"${table_prefix}SCHEDULER_STATE\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"INSTANCE_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"LAST_CHECKIN_TIME\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"CHECKIN_INTERVAL\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, INSTANCE_NAME\" tableName=\"${table_prefix}SCHEDULER_STATE\"/>\n\n        <createTable tableName=\"${table_prefix}JOB_DETAILS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"DESCRIPTION\" type=\"VARCHAR(250)\"/>\n            <column name=\"JOB_CLASS_NAME\" type=\"VARCHAR(250)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"IS_DURABLE\" type=\"BOOLEAN\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"IS_NONCONCURRENT\" type=\"BOOLEAN\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"IS_UPDATE_DATA\" type=\"BOOLEAN\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"REQUESTS_RECOVERY\" type=\"BOOLEAN\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_DATA\" type=\"${blob_type}\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, JOB_NAME, JOB_GROUP\" tableName=\"${table_prefix}JOB_DETAILS\"/>\n\n        <createIndex tableName=\"${table_prefix}JOB_DETAILS\" indexName=\"IDX_${table_prefix}J_GRP\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"JOB_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}JOB_DETAILS\" indexName=\"IDX_${table_prefix}J_REQ_RECOVERY\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"REQUESTS_RECOVERY\"/>\n        </createIndex>\n\n        <createTable tableName=\"${table_prefix}TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"JOB_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"DESCRIPTION\" type=\"VARCHAR(250)\"/>\n            <column name=\"NEXT_FIRE_TIME\" type=\"BIGINT\"/>\n            <column name=\"PREV_FIRE_TIME\" type=\"BIGINT\"/>\n            <column name=\"PRIORITY\" type=\"INTEGER\"/>\n            <column name=\"TRIGGER_STATE\" type=\"VARCHAR(16)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_TYPE\" type=\"VARCHAR(8)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"START_TIME\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"END_TIME\" type=\"BIGINT\"/>\n            <column name=\"CALENDAR_NAME\" type=\"VARCHAR(200)\"/>\n            <column name=\"MISFIRE_INSTR\" type=\"smallint\"/>\n            <column name=\"JOB_DATA\" type=\"${blob_type}\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}TRIGGERS\"/>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_C\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"CALENDAR_NAME\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_G\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_JG\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"JOB_GROUP\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_N_G_STATE\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n            <column name=\"TRIGGER_STATE\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_N_STATE\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_NAME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n            <column name=\"TRIGGER_STATE\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_NEXT_FIRE_TIME\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"NEXT_FIRE_TIME\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_NFT_MISFIRE\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"MISFIRE_INSTR\"/>\n            <column name=\"NEXT_FIRE_TIME\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_NFT_ST\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_STATE\"/>\n            <column name=\"NEXT_FIRE_TIME\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_NFT_ST_MISFIRE\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"MISFIRE_INSTR\"/>\n            <column name=\"NEXT_FIRE_TIME\"/>\n            <column name=\"TRIGGER_STATE\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_NFT_ST_MISFIRE_GRP\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"MISFIRE_INSTR\"/>\n            <column name=\"NEXT_FIRE_TIME\"/>\n            <column name=\"TRIGGER_GROUP\"/>\n            <column name=\"TRIGGER_STATE\"/>\n        </createIndex>\n\n        <createIndex tableName=\"${table_prefix}TRIGGERS\" indexName=\"IDX_${table_prefix}T_STATE\">\n            <column name=\"SCHED_NAME\"/>\n            <column name=\"TRIGGER_STATE\"/>\n        </createIndex>\n\n        <createTable tableName=\"${table_prefix}BLOB_TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"BLOB_DATA\" type=\"${blob_type}\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}BLOB_TRIGGERS\"/>\n\n        <createTable tableName=\"${table_prefix}SIMPROP_TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"STR_PROP_1\" type=\"VARCHAR(512)\"/>\n            <column name=\"STR_PROP_2\" type=\"VARCHAR(512)\"/>\n            <column name=\"STR_PROP_3\" type=\"VARCHAR(512)\"/>\n            <column name=\"INT_PROP_1\" type=\"INTEGER\"/>\n            <column name=\"INT_PROP_2\" type=\"INTEGER\"/>\n            <column name=\"LONG_PROP_1\" type=\"BIGINT\"/>\n            <column name=\"LONG_PROP_2\" type=\"BIGINT\"/>\n            <column name=\"DEC_PROP_1\" type=\"NUMERIC(13,4)\"/>\n            <column name=\"DEC_PROP_2\" type=\"NUMERIC(13,4)\"/>\n            <column name=\"BOOL_PROP_1\" type=\"BOOLEAN\"/>\n            <column name=\"BOOL_PROP_2\" type=\"BOOLEAN\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}SIMPROP_TRIGGERS\"/>\n\n        <createTable tableName=\"${table_prefix}CRON_TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"CRON_EXPRESSION\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TIME_ZONE_ID\" type=\"VARCHAR(80)\"/>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}CRON_TRIGGERS\"/>\n\n        <createTable tableName=\"${table_prefix}SIMPLE_TRIGGERS\">\n            <column name=\"SCHED_NAME\" type=\"VARCHAR(120)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_NAME\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TRIGGER_GROUP\" type=\"VARCHAR(200)\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"REPEAT_COUNT\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"REPEAT_INTERVAL\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n            <column name=\"TIMES_TRIGGERED\" type=\"BIGINT\">\n                <constraints nullable=\"false\"/>\n            </column>\n        </createTable>\n        <addPrimaryKey columnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" tableName=\"${table_prefix}SIMPLE_TRIGGERS\"/>\n\n        <addForeignKeyConstraint baseTableName=\"${table_prefix}TRIGGERS\" constraintName=\"${table_prefix}TRIGGERS_SCHED_NAME_FKEY\" baseColumnNames=\"SCHED_NAME, JOB_NAME, JOB_GROUP\" referencedTableName=\"${table_prefix}JOB_DETAILS\" referencedColumnNames=\"SCHED_NAME, JOB_NAME, JOB_GROUP\"/>\n\n        <addForeignKeyConstraint baseTableName=\"${table_prefix}SIMPLE_TRIGGERS\" constraintName=\"${table_prefix}SIMPLE_TRIGGERS_SCHED_NAME_FKEY\" baseColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" referencedTableName=\"${table_prefix}TRIGGERS\" referencedColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\"/>\n\n        <addForeignKeyConstraint baseTableName=\"${table_prefix}CRON_TRIGGERS\" constraintName=\"${table_prefix}CRON_TRIGGERS_SCHED_NAME_FKEY\" baseColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" referencedTableName=\"${table_prefix}TRIGGERS\" referencedColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\"/>\n\n        <addForeignKeyConstraint baseTableName=\"${table_prefix}SIMPROP_TRIGGERS\" constraintName=\"${table_prefix}SIMPROP_TRIGGERS_SCHED_NAME_FKEY\" baseColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" referencedTableName=\"${table_prefix}TRIGGERS\" referencedColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\"/>\n\n        <addForeignKeyConstraint baseTableName=\"${table_prefix}BLOB_TRIGGERS\" constraintName=\"${table_prefix}BLOB_TRIGGERS_SCHED_NAME_FKEY\" baseColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\" referencedTableName=\"${table_prefix}TRIGGERS\" referencedColumnNames=\"SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP\"/>\n    </changeSet>\n</databaseChangeLog>\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_cloudscape.sql",
    "content": "# \n# Thanks to Srinivas Venkatarangaiah for submitting this file's contents\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CloudscapeDelegate\n#\n# Known to work with Cloudscape 3.6.4 (should work with others)\n#\n\n\ncreate table qrtz_job_details (\n    sched_name varchar(120) not null,\n\tjob_name varchar(200) not null,\n\tjob_group varchar(200) not null,\n\tdescription varchar(250) ,\n\tjob_class_name varchar(250) not null,\n\tis_durable varchar(5) not null,\n    is_nonconcurrent varchar(5) not null,\n    is_update_data varchar(5) not null,\n\trequests_recovery varchar(5) not null,\n\tjob_data long varbinary,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tjob_name varchar(200) not null,\n\tjob_group varchar(200) not null,\n\tdescription varchar(250) ,\n\tnext_fire_time longint,\n\tprev_fire_time longint,\n\tpriority integer,\n\ttrigger_state varchar(16) not null,\n\ttrigger_type varchar(8) not null,\n\tstart_time longint not null,\n\tend_time longint,\n\tcalendar_name varchar(200),\n\tmisfire_instr smallint,\n\tjob_data long varbinary,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\trepeat_count longint not null,\n\trepeat_interval longint not null,\n\ttimes_triggered longint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tcron_expression varchar(120) not null,\n\ttime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 longint NULL,\n    LONG_PROP_2 longint NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 varchar(5) NULL,\n    BOOL_PROP_2 varchar(5) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tblob_data long varbinary ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n    sched_name varchar(120) not null,\n\tcalendar_name varchar(200) not null,\n\tcalendar long varbinary not null,\nprimary key (sched_name,calendar_name)\n); \n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group  varchar(200) not null, \nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\n    sched_name varchar(120) not null,\n\tentry_id varchar(95) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tinstance_name varchar(200) not null,\n\tfired_time longint not null,\n\tsched_time longint not null,\n\tpriority integer not null,\n\tstate varchar(16) not null,\n\tjob_name varchar(200) null,\n\tjob_group varchar(200) null,\n\tis_nonconcurrent varchar(5) null,\n\trequests_recovery varchar(5) null,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state \n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(200) not null,\n    last_checkin_time longint not null,\n    checkin_interval longint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_cubrid.sql",
    "content": "\n-- Thanks to Timothy Anyona for this script\n-- CUBRID 8.4.1+\n\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CUBRIDDelegate\n\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\n\nCREATE TABLE QRTZ_JOB_DETAILS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,\n    IS_DURABLE BIT(1) NOT NULL,\n    IS_NONCONCURRENT BIT(1) NOT NULL,\n    IS_UPDATE_DATA BIT(1) NOT NULL,\n    REQUESTS_RECOVERY BIT(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT NULL,\n    PREV_FIRE_TIME BIGINT NULL,\n    PRIORITY INTEGER NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT NOT NULL,\n    END_TIME BIGINT NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR SMALLINT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT BIGINT NOT NULL,\n    REPEAT_INTERVAL BIGINT NOT NULL,\n    TIMES_TRIGGERED BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(200) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BIT(1) NULL,\n    BOOL_PROP_2 BIT(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    CALENDAR BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME BIGINT NOT NULL,\n    SCHED_TIME BIGINT NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT BIT(1) NULL,\n    REQUESTS_RECOVERY BIT(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT NOT NULL,\n    CHECKIN_INTERVAL BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);\n\n\nCREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_db2.sql",
    "content": "#\n# Thanks to Horia Muntean for submitting this....\n#\n# .. known to work with DB2 7.1 and the JDBC driver \"COM.ibm.db2.jdbc.net.DB2Driver\"\n# .. likely to work with others...\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n# If you're using DB2 6.x you'll want to set this property to\n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v6Delegate\n#\n\n\ncreate table qrtz_job_details (\n  sched_name varchar(120) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120) null,\n  job_class_name varchar(128) not null,\n  is_durable varchar(1) not null,\n  is_nonconcurrent varchar(1) not null,\n  is_update_data varchar(1) not null,\n  requests_recovery varchar(1) not null,\n  job_data blob,\n    primary key (sched_name,job_name,job_group)\n)\n\ncreate table qrtz_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120) null,\n  next_fire_time bigint,\n  prev_fire_time bigint,\n  priority integer,\n  trigger_state varchar(16) not null,\n  trigger_type varchar(8) not null,\n  start_time bigint not null,\n  end_time bigint,\n  calendar_name varchar(80),\n  misfire_instr smallint,\n  job_data blob,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n)\n\ncreate table qrtz_simple_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  repeat_count bigint not null,\n  repeat_interval bigint not null,\n  times_triggered bigint not null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\ncreate table qrtz_cron_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  cron_expression varchar(120) not null,\n  time_zone_id varchar(80),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n)\n\ncreate table qrtz_blob_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  blob_data blob null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\ncreate table qrtz_calendars(\n  sched_name varchar(120) not null,\n  calendar_name varchar(80) not null,\n  calendar blob not null,\n    primary key (sched_name,calendar_name)\n)\n\ncreate table qrtz_fired_triggers(\n  sched_name varchar(120) not null,\n  entry_id varchar(95) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  instance_name varchar(80) not null,\n  fired_time bigint not null,\n  sched_time bigint not null,\n  priority integer not null,\n  state varchar(16) not null,\n  job_name varchar(80) null,\n  job_group varchar(80) null,\n  is_nonconcurrent varchar(1) null,\n  requests_recovery varchar(1) null,\n    primary key (sched_name,entry_id)\n);\n\n\ncreate table qrtz_paused_trigger_grps(\n  sched_name varchar(120) not null,\n  trigger_group  varchar(80) not null, \n    primary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state (\n  sched_name varchar(120) not null,\n  instance_name varchar(80) not null,\n  last_checkin_time bigint not null,\n  checkin_interval bigint not null,\n    primary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n  sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \n      primary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_db2_v72.sql",
    "content": "--\n-- Thanks to Horia Muntean for submitting this, Mikkel Heisterberg for updating it \n--\n-- .. known to work with DB2 7.2 and the JDBC driver \"COM.ibm.db2.jdbc.net.DB2Driver\"\n-- .. likely to work with others...\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v7Delegate\n--\n-- or\n--\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n--\n-- If you're using DB2 6.x you'll want to set this property to\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v6Delegate\n--\n-- Note that the blob column size (e.g. blob(2000)) dictates the amount of data that can be stored in \n-- that blob - i.e. limits the amount of data you can put into your JobDataMap \n--\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details (\n  sched_name varchar(120) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120),\n  job_class_name varchar(128) not null,\n  is_durable varchar(1) not null,\n  is_nonconcurrent varchar(1) not null,\n  is_update_data varchar(1) not null,\n  requests_recovery varchar(1) not null,\n  job_data blob(2000),\n    primary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120),\n  next_fire_time bigint,\n  prev_fire_time bigint,\n  priority integer,\n  trigger_state varchar(16) not null,\n  trigger_type varchar(8) not null,\n  start_time bigint not null,\n  end_time bigint,\n  calendar_name varchar(80),\n  misfire_instr smallint,\n  job_data blob(2000),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  repeat_count bigint not null,\n  repeat_interval bigint not null,\n  times_triggered bigint not null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  cron_expression varchar(120) not null,\n  time_zone_id varchar(80),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  blob_data blob(2000),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n  sched_name varchar(120) not null,\n  calendar_name varchar(80) not null,\n  calendar blob(2000) not null,\n    primary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\n  sched_name varchar(120) not null,\n  entry_id varchar(95) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  instance_name varchar(80) not null,\n  fired_time bigint not null,\n  sched_time bigint not null,\n  priority integer not null,\n  state varchar(16) not null,\n  job_name varchar(80),\n  job_group varchar(80),\n  is_nonconcurrent varchar(1),\n  requests_recovery varchar(1),\n    primary key (sched_name,entry_id)\n);\n\n\ncreate table qrtz_paused_trigger_grps(\n  sched_name varchar(120) not null,\n  trigger_group  varchar(80) not null, \n    primary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state (\n  sched_name varchar(120) not null,\n  instance_name varchar(80) not null,\n  last_checkin_time bigint not null,\n  checkin_interval bigint not null,\n    primary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \n      primary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_db2_v8.sql",
    "content": "#\n# Updated by Claudiu Crisan (claudiu.crisan@schartner.net)\n# SQL scripts for DB2 ver 8.1\n#\n# Changes:\n# - \"varchar(1)\" replaced with \"integer\"\n# - \"field_name varchar(xxx) not null\" replaced with \"field_name varchar(xxx)\"\n#\n\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details(\nsched_name varchar(120) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\njob_class_name varchar(128) not null,\nis_durable integer not null,\nis_nonconcurrent integer not null,\nis_update_data integer not null,\nrequests_recovery integer not null,\njob_data blob(2000),\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(80),\nmisfire_instr smallint,\njob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nblob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(80) not null,\ncalendar blob(2000) not null,\nprimary key (calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ninstance_name varchar(80) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(80),\njob_group varchar(80),\nis_nonconcurrent integer,\nrequests_recovery integer,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_paused_trigger_grps(\nsched_name varchar(120) not null,\ntrigger_group varchar(80) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state(\nsched_name varchar(120) not null,\ninstance_name varchar(80) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks(\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_db2_v95.sql",
    "content": "DROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details(\nsched_name varchar(120) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\njob_class_name varchar(128) not null,\nis_durable integer not null,\nis_nonconcurrent integer not null,\nis_update_data integer not null,\nrequests_recovery integer not null,\njob_data blob(2000),\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(80),\nmisfire_instr smallint,\njob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512),\n    STR_PROP_2 VARCHAR(512),\n    STR_PROP_3 VARCHAR(512),\n    INT_PROP_1 INT,\n    INT_PROP_2 INT,\n    LONG_PROP_1 BIGINT,\n    LONG_PROP_2 BIGINT,\n    DEC_PROP_1 NUMERIC(13,4),\n    DEC_PROP_2 NUMERIC(13,4),\n    BOOL_PROP_1 VARCHAR(1),\n    BOOL_PROP_2 VARCHAR(1),\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nblob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(80) not null,\ncalendar blob(2000) not null,\nprimary key (calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ninstance_name varchar(80) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(80),\njob_group varchar(80),\nis_nonconcurrent integer,\nrequests_recovery integer,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_paused_trigger_grps(\nsched_name varchar(120) not null,\ntrigger_group varchar(80) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state(\nsched_name varchar(120) not null,\ninstance_name varchar(80) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks(\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_derby.sql",
    "content": "-- \n-- Apache Derby scripts by Steve Stewart, updated by Ronald Pomeroy\n-- Based on Srinivas Venkatarangaiah's file for Cloudscape\n-- \n-- Known to work with Apache Derby 10.0.2.1, or 10.6.2.1\n--\n-- Updated by Zemian Deng <saltnlight5@gmail.com> on 08/21/2011\n--   * Fixed nullable fields on qrtz_simprop_triggers table. \n--   * Added Derby QuickStart comments and drop tables statements.\n--\n-- DerbyDB + Quartz Quick Guide:\n-- * Derby comes with Oracle JDK! For Java6, it default install into C:/Program Files/Sun/JavaDB on Windows.\n-- 1. Create a derby.properties file under JavaDB directory, and have the following:\n--    derby.connection.requireAuthentication = true\n--    derby.authentication.provider = BUILTIN\n--    derby.user.quartz2=quartz2123\n-- 2. Start the DB server by running bin/startNetworkServer script.\n-- 3. On a new terminal, run bin/ij tool to bring up an SQL prompt, then run:\n--    connect 'jdbc:derby://localhost:1527/quartz2;user=quartz2;password=quartz2123;create=true';\n--    run 'quartz/docs/dbTables/tables_derby.sql';\n-- Now in quartz.properties, you may use these properties:\n--    org.quartz.dataSource.quartzDataSource.driver = org.apache.derby.jdbc.ClientDriver\n--    org.quartz.dataSource.quartzDataSource.URL = jdbc:derby://localhost:1527/quartz2\n--    org.quartz.dataSource.quartzDataSource.user = quartz2\n--    org.quartz.dataSource.quartzDataSource.password = quartz2123\n--\n\n-- Auto drop and reset tables \n-- Derby doesn't support if exists condition on table drop, so user must manually do this step if needed to.\n-- drop table qrtz_fired_triggers;\n-- drop table qrtz_paused_trigger_grps;\n-- drop table qrtz_scheduler_state;\n-- drop table qrtz_locks;\n-- drop table qrtz_simple_triggers;\n-- drop table qrtz_simprop_triggers;\n-- drop table qrtz_cron_triggers;\n-- drop table qrtz_blob_triggers;\n-- drop table qrtz_triggers;\n-- drop table qrtz_job_details;\n-- drop table qrtz_calendars;\n\ncreate table qrtz_job_details (\nsched_name varchar(120) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\njob_class_name varchar(250) not null,\nis_durable varchar(5) not null,\nis_nonconcurrent varchar(5) not null,\nis_update_data varchar(5) not null,\nrequests_recovery varchar(5) not null,\njob_data blob,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(200),\nmisfire_instr smallint,\njob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    trigger_name varchar(200) not null,\n    trigger_group varchar(200) not null,\n    str_prop_1 varchar(512),\n    str_prop_2 varchar(512),\n    str_prop_3 varchar(512),\n    int_prop_1 int,\n    int_prop_2 int,\n    long_prop_1 bigint,\n    long_prop_2 bigint,\n    dec_prop_1 numeric(13,4),\n    dec_prop_2 numeric(13,4),\n    bool_prop_1 varchar(5),\n    bool_prop_2 varchar(5),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) \n    references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nblob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(200) not null,\ncalendar blob not null,\nprimary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group varchar(200) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ninstance_name varchar(200) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(200),\njob_group varchar(200),\nis_nonconcurrent varchar(5),\nrequests_recovery varchar(5),\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state\n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(200) not null,\n    last_checkin_time bigint not null,\n    checkin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_derby_previous.sql",
    "content": "-- \n-- Apache Derby scripts by Steve Stewart.\n-- Based on Srinivas Venkatarangaiah's file for Cloudscape\n-- \n-- In your Quartz properties file, you'll need to set\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CloudscapeDelegate\n-- \n-- Known to work with Apache Derby 10.0.2.1\n-- \n\ncreate table qrtz_job_details (\nsched_name varchar(120) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\njob_class_name varchar(250) not null,\nis_durable varchar(5) not null,\nis_nonconcurrent varchar(5) not null,\nis_update_data varchar(5) not null,\nrequests_recovery varchar(5) not null,\njob_data blob,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(200),\nmisfire_instr smallint,\njob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_simprop_triggers\n(          \n    sched_name varchar(120) not null,\n    trigger_name varchar(200) not null,\n    trigger_group varchar(200) not null,\n    str_prop_1 varchar(512),\n    str_prop_2 varchar(512),\n    str_prop_3 varchar(512),\n    int_prop_1 int,\n    int_prop_2 int,\n    long_prop_1 bigint,\n    long_prop_2 bigint,\n    dec_prop_1 numeric(13,4),\n    dec_prop_2 numeric(13,4),\n    bool_prop_1 varchar(5),\n    bool_prop_2 varchar(5),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) \n    references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nblob_data blob ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars (\nsched_name varchar(120) not null,\ncalendar_name varchar(200) not null,\ncalendar blob not null,\nprimary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_paused_trigger_grps (\nsched_name varchar(120) not null,\ntrigger_group varchar(200) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers (\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ninstance_name varchar(200) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(200),\njob_group varchar(200),\nis_nonconcurrent varchar(5),\nrequests_recovery varchar(5),\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state (\nsched_name varchar(120) not null,\ninstance_name varchar(200) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks (\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_firebird.sql",
    "content": "\n--\n-- Thanks to Leonardo Alves\n--\n\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\n\n\nCREATE TABLE QRTZ_JOB_DETAILS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(60) NOT NULL,\n    JOB_GROUP VARCHAR(60) NOT NULL,\n    DESCRIPTION VARCHAR(120),\n    JOB_CLASS_NAME   VARCHAR(128) NOT NULL, \n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    JOB_NAME  VARCHAR(60) NOT NULL, \n    JOB_GROUP VARCHAR(60) NOT NULL,\n    DESCRIPTION VARCHAR(120),\n    NEXT_FIRE_TIME BIGINT,\n    PREV_FIRE_TIME BIGINT,\n    PRIORITY INTEGER,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT NOT NULL,\n    END_TIME BIGINT,\n    CALENDAR_NAME VARCHAR(60),\n    MISFIRE_INSTR SMALLINT,\n    JOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n    REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    REPEAT_COUNT BIGINT NOT NULL,\n    REPEAT_INTERVAL BIGINT NOT NULL,\n    TIMES_TRIGGERED BIGINT NOT NULL,\n    CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR(60),\n    CONSTRAINT PK_QRTZ_SIMPLE_TRG PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPLE_TRG_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    BLOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_BLOB_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_BLOB_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(60) NOT NULL, \n    CALENDAR BLOB NOT NULL,\n    CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(60) NOT NULL, \n    CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    INSTANCE_NAME VARCHAR(80) NOT NULL,\n    FIRED_TIME BIGINT NOT NULL,\n    SCHED_TIME BIGINT NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(60),\n    JOB_GROUP VARCHAR(60),\n    IS_NONCONCURRENT VARCHAR(1),\n    REQUESTS_RECOVERY VARCHAR(1),\n    CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(80) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT NOT NULL,\n    CHECKIN_INTERVAL BIGINT NOT NULL,\n    CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\nCOMMIT;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_gauss_default_compatibility.sql",
    "content": "-- Notes: Original sql of this file is based on tables_postgres.sql.\n-- Thanks to Patrick Lightbody for submitting this...\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.GaussDBDelegate\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  JOB_NAME          VARCHAR(200) NOT NULL,\n  JOB_GROUP         VARCHAR(200) NOT NULL,\n  DESCRIPTION       VARCHAR(250) NULL,\n  JOB_CLASS_NAME    VARCHAR(250) NOT NULL,\n  IS_DURABLE        BOOL         NOT NULL,\n  IS_NONCONCURRENT  BOOL         NOT NULL,\n  IS_UPDATE_DATA    BOOL         NOT NULL,\n  REQUESTS_RECOVERY BOOL         NOT NULL,\n  JOB_DATA          BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n(\n  SCHED_NAME     VARCHAR(120) NOT NULL,\n  TRIGGER_NAME   VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP  VARCHAR(200) NOT NULL,\n  JOB_NAME       VARCHAR(200) NOT NULL,\n  JOB_GROUP      VARCHAR(200) NOT NULL,\n  DESCRIPTION    VARCHAR(250) NULL,\n  NEXT_FIRE_TIME BIGINT       NULL,\n  PREV_FIRE_TIME BIGINT       NULL,\n  PRIORITY       INTEGER      NULL,\n  TRIGGER_STATE  VARCHAR(16)  NOT NULL,\n  TRIGGER_TYPE   VARCHAR(8)   NOT NULL,\n  START_TIME     BIGINT       NOT NULL,\n  END_TIME       BIGINT       NULL,\n  CALENDAR_NAME  VARCHAR(200) NULL,\n  MISFIRE_INSTR  SMALLINT     NULL,\n  JOB_DATA       BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n  REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n(\n  SCHED_NAME      VARCHAR(120) NOT NULL,\n  TRIGGER_NAME    VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n  REPEAT_COUNT    BIGINT       NOT NULL,\n  REPEAT_INTERVAL BIGINT       NOT NULL,\n  TIMES_TRIGGERED BIGINT       NOT NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n(\n  SCHED_NAME      VARCHAR(120) NOT NULL,\n  TRIGGER_NAME    VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n  CRON_EXPRESSION VARCHAR(120) NOT NULL,\n  TIME_ZONE_ID    VARCHAR(80),\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n(\n  SCHED_NAME    VARCHAR(120)   NOT NULL,\n  TRIGGER_NAME  VARCHAR(200)   NOT NULL,\n  TRIGGER_GROUP VARCHAR(200)   NOT NULL,\n  STR_PROP_1    VARCHAR(512)   NULL,\n  STR_PROP_2    VARCHAR(512)   NULL,\n  STR_PROP_3    VARCHAR(512)   NULL,\n  INT_PROP_1    INT            NULL,\n  INT_PROP_2    INT            NULL,\n  LONG_PROP_1   BIGINT         NULL,\n  LONG_PROP_2   BIGINT         NULL,\n  DEC_PROP_1    NUMERIC(13, 4) NULL,\n  DEC_PROP_2    NUMERIC(13, 4) NULL,\n  BOOL_PROP_1   BOOL           NULL,\n  BOOL_PROP_2   BOOL           NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  TRIGGER_NAME  VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP VARCHAR(200) NOT NULL,\n  BLOB_DATA     BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR(200) NOT NULL,\n  CALENDAR      BYTEA        NOT NULL,\n  PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)\n);\n\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  TRIGGER_GROUP VARCHAR(200) NOT NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  ENTRY_ID          VARCHAR(95)  NOT NULL,\n  TRIGGER_NAME      VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP     VARCHAR(200) NOT NULL,\n  INSTANCE_NAME     VARCHAR(200) NOT NULL,\n  FIRED_TIME        BIGINT       NOT NULL,\n  SCHED_TIME        BIGINT       NOT NULL,\n  PRIORITY          INTEGER      NOT NULL,\n  STATE             VARCHAR(16)  NOT NULL,\n  JOB_NAME          VARCHAR(200) NULL,\n  JOB_GROUP         VARCHAR(200) NULL,\n  IS_NONCONCURRENT  BOOL         NULL,\n  REQUESTS_RECOVERY BOOL         NULL,\n  PRIMARY KEY (SCHED_NAME, ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  INSTANCE_NAME     VARCHAR(200) NOT NULL,\n  LAST_CHECKIN_TIME BIGINT       NOT NULL,\n  CHECKIN_INTERVAL  BIGINT       NOT NULL,\n  PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n(\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  LOCK_NAME  VARCHAR(40)  NOT NULL,\n  PRIMARY KEY (SCHED_NAME, LOCK_NAME)\n);\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY\n  ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP\n  ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);\n\nCREATE INDEX IDX_QRTZ_T_J\n  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_JG\n  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C\n  ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME\n  ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);\n\n\nCOMMIT;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_gauss_m_compatibility.sql",
    "content": "-- In your Quartz properties file, you'll need to set\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS\n(\n    SCHED_NAME        VARCHAR(120) NOT NULL,\n    JOB_NAME          VARCHAR(200) NOT NULL,\n    JOB_GROUP         VARCHAR(200) NOT NULL,\n    DESCRIPTION       VARCHAR(250) NULL,\n    JOB_CLASS_NAME    VARCHAR(250) NOT NULL,\n    IS_DURABLE        BOOL   NOT NULL,\n    IS_NONCONCURRENT  BOOL   NOT NULL,\n    IS_UPDATE_DATA    BOOL   NOT NULL,\n    REQUESTS_RECOVERY BOOL   NOT NULL,\n    JOB_DATA          BLOB         NULL,\n    PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n(\n    SCHED_NAME     VARCHAR(120) NOT NULL,\n    TRIGGER_NAME   VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL,\n    JOB_NAME       VARCHAR(200) NOT NULL,\n    JOB_GROUP      VARCHAR(200) NOT NULL,\n    DESCRIPTION    VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT  NULL,\n    PREV_FIRE_TIME BIGINT  NULL,\n    PRIORITY       INTEGER      NULL,\n    TRIGGER_STATE  VARCHAR(16)  NOT NULL,\n    TRIGGER_TYPE   VARCHAR(8)   NOT NULL,\n    START_TIME     BIGINT  NOT NULL,\n    END_TIME       BIGINT  NULL,\n    CALENDAR_NAME  VARCHAR(200) NULL,\n    MISFIRE_INSTR  SMALLINT     NULL,\n    JOB_DATA       BLOB         NULL,\n    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n    REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n(\n    SCHED_NAME      VARCHAR(120) NOT NULL,\n    TRIGGER_NAME    VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n    REPEAT_COUNT    NUMERIC(7)   NOT NULL,\n    REPEAT_INTERVAL NUMERIC(12)  NOT NULL,\n    TIMES_TRIGGERED NUMERIC(10)  NOT NULL,\n    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n(\n    SCHED_NAME      VARCHAR(120) NOT NULL,\n    TRIGGER_NAME    VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID    VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n(\n    SCHED_NAME    VARCHAR(120)   NOT NULL,\n    TRIGGER_NAME  VARCHAR(200)   NOT NULL,\n    TRIGGER_GROUP VARCHAR(200)   NOT NULL,\n    STR_PROP_1    VARCHAR(512)   NULL,\n    STR_PROP_2    VARCHAR(512)   NULL,\n    STR_PROP_3    VARCHAR(512)   NULL,\n    INT_PROP_1    INTEGER        NULL,\n    INT_PROP_2    INTEGER        NULL,\n    LONG_PROP_1   BIGINT    NULL,\n    LONG_PROP_2   BIGINT    NULL,\n    DEC_PROP_1    NUMERIC(13, 4) NULL,\n    DEC_PROP_2    NUMERIC(13, 4) NULL,\n    BOOL_PROP_1   BOOL     NULL,\n    BOOL_PROP_2   BOOL     NULL,\n    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n(\n    SCHED_NAME    VARCHAR(120) NOT NULL,\n    TRIGGER_NAME  VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA     BLOB         NULL,\n    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n(\n    SCHED_NAME    VARCHAR(120) NOT NULL,\n    CALENDAR_NAME VARCHAR(200) NOT NULL,\n    CALENDAR      BLOB         NOT NULL,\n    PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n(\n    SCHED_NAME    VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n(\n    SCHED_NAME        VARCHAR(120) NOT NULL,\n    ENTRY_ID          VARCHAR(95)  NOT NULL,\n    TRIGGER_NAME      VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP     VARCHAR(200) NOT NULL,\n    INSTANCE_NAME     VARCHAR(200) NOT NULL,\n    FIRED_TIME        BIGINT  NOT NULL,\n    SCHED_TIME        BIGINT  NOT NULL,\n    PRIORITY          INTEGER      NOT NULL,\n    STATE             VARCHAR(16)  NOT NULL,\n    JOB_NAME          VARCHAR(200) NULL,\n    JOB_GROUP         VARCHAR(200) NULL,\n    IS_NONCONCURRENT  BOOL   NULL,\n    REQUESTS_RECOVERY BOOL   NULL,\n    PRIMARY KEY (SCHED_NAME, ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n(\n    SCHED_NAME        VARCHAR(120) NOT NULL,\n    INSTANCE_NAME     VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT  NOT NULL,\n    CHECKIN_INTERVAL  BIGINT  NOT NULL,\n    PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40)  NOT NULL,\n    PRIMARY KEY (SCHED_NAME, LOCK_NAME)\n);\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME, JOB_GROUP);\n\nCREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME, CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME, TRIGGER_GROUP);"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_h2.sql",
    "content": "-- Thanks to Amir Kibbar and Peter Rietzler for contributing the schema for H2 database, \n-- and verifying that it works with Quartz's StdJDBCDelegate\n--\n-- Note, Quartz depends on row-level locking which means you must use the MVCC=TRUE \n-- setting on your H2 database, or you will experience dead-locks\n--\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n\nCREATE TABLE QRTZ_CALENDARS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR (200)  NOT NULL ,\n  CALENDAR IMAGE NOT NULL\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  CRON_EXPRESSION VARCHAR (120)  NOT NULL ,\n  TIME_ZONE_ID VARCHAR (80) \n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  ENTRY_ID VARCHAR (95)  NOT NULL ,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  INSTANCE_NAME VARCHAR (200)  NOT NULL ,\n  FIRED_TIME BIGINT NOT NULL ,\n  SCHED_TIME BIGINT NOT NULL ,\n  PRIORITY INTEGER NOT NULL ,\n  STATE VARCHAR (16)  NOT NULL,\n  JOB_NAME VARCHAR (200)  NULL ,\n  JOB_GROUP VARCHAR (200)  NULL ,\n  IS_NONCONCURRENT BOOLEAN  NULL ,\n  REQUESTS_RECOVERY BOOLEAN  NULL \n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL \n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  INSTANCE_NAME VARCHAR (200)  NOT NULL ,\n  LAST_CHECKIN_TIME BIGINT NOT NULL ,\n  CHECKIN_INTERVAL BIGINT NOT NULL\n);\n\nCREATE TABLE QRTZ_LOCKS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  LOCK_NAME VARCHAR (40)  NOT NULL \n);\n\nCREATE TABLE QRTZ_JOB_DETAILS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  JOB_NAME VARCHAR (200)  NOT NULL ,\n  JOB_GROUP VARCHAR (200)  NOT NULL ,\n  DESCRIPTION VARCHAR (250) NULL ,\n  JOB_CLASS_NAME VARCHAR (250)  NOT NULL ,\n  IS_DURABLE BOOLEAN  NOT NULL ,\n  IS_NONCONCURRENT BOOLEAN  NOT NULL ,\n  IS_UPDATE_DATA BOOLEAN  NOT NULL ,\n  REQUESTS_RECOVERY BOOLEAN  NOT NULL ,\n  JOB_DATA IMAGE NULL\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  REPEAT_COUNT BIGINT NOT NULL ,\n  REPEAT_INTERVAL BIGINT NOT NULL ,\n  TIMES_TRIGGERED BIGINT NOT NULL\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INTEGER NULL,\n    INT_PROP_2 INTEGER NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  BLOB_DATA IMAGE NULL\n);\n\nCREATE TABLE QRTZ_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  JOB_NAME VARCHAR (200)  NOT NULL ,\n  JOB_GROUP VARCHAR (200)  NOT NULL ,\n  DESCRIPTION VARCHAR (250) NULL ,\n  NEXT_FIRE_TIME BIGINT NULL ,\n  PREV_FIRE_TIME BIGINT NULL ,\n  PRIORITY INTEGER NULL ,\n  TRIGGER_STATE VARCHAR (16)  NOT NULL ,\n  TRIGGER_TYPE VARCHAR (8)  NOT NULL ,\n  START_TIME BIGINT NOT NULL ,\n  END_TIME BIGINT NULL ,\n  CALENDAR_NAME VARCHAR (200)  NULL ,\n  MISFIRE_INSTR SMALLINT NULL ,\n  JOB_DATA IMAGE NULL\n);\n\nALTER TABLE QRTZ_CALENDARS  ADD\n  CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    CALENDAR_NAME\n  );\n\nALTER TABLE QRTZ_CRON_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_FIRED_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    ENTRY_ID\n  );\n\nALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS  ADD\n  CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_SCHEDULER_STATE  ADD\n  CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY  \n  (\n    SCHED_NAME,\n    INSTANCE_NAME\n  );\n\nALTER TABLE QRTZ_LOCKS  ADD\n  CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    LOCK_NAME\n  );\n\nALTER TABLE QRTZ_JOB_DETAILS  ADD\n  CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  );\n\nALTER TABLE QRTZ_SIMPLE_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_SIMPROP_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_CRON_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\n\nALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\nALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\n\nALTER TABLE QRTZ_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY\n  (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  ) REFERENCES QRTZ_JOB_DETAILS (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  );\n  \nCOMMIT;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_hsqldb.sql",
    "content": "--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.HSQLDBDelegate\n--\n\nDROP TABLE qrtz_locks IF EXISTS;\nDROP TABLE qrtz_scheduler_state IF EXISTS;\nDROP TABLE qrtz_fired_triggers IF EXISTS;\nDROP TABLE qrtz_paused_trigger_grps IF EXISTS;\nDROP TABLE qrtz_calendars IF EXISTS;\nDROP TABLE qrtz_blob_triggers IF EXISTS;\nDROP TABLE qrtz_cron_triggers IF EXISTS;\nDROP TABLE qrtz_simple_triggers IF EXISTS;\nDROP TABLE qrtz_simprop_triggers IF EXISTS;\nDROP TABLE qrtz_triggers IF EXISTS;\nDROP TABLE qrtz_job_details IF EXISTS;\n\nCREATE TABLE qrtz_job_details\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nJOB_CLASS_NAME VARCHAR(250) NOT NULL,\nIS_DURABLE BOOLEAN NOT NULL,\nIS_NONCONCURRENT BOOLEAN NOT NULL,\nIS_UPDATE_DATA BOOLEAN NOT NULL,\nREQUESTS_RECOVERY BOOLEAN NOT NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nNEXT_FIRE_TIME NUMERIC(13) NULL,\nPREV_FIRE_TIME NUMERIC(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE VARCHAR(16) NOT NULL,\nTRIGGER_TYPE VARCHAR(8) NOT NULL,\nSTART_TIME NUMERIC(13) NOT NULL,\nEND_TIME NUMERIC(13) NULL,\nCALENDAR_NAME VARCHAR(200) NULL,\nMISFIRE_INSTR NUMERIC(2) NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_simple_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nREPEAT_COUNT NUMERIC(7) NOT NULL,\nREPEAT_INTERVAL NUMERIC(12) NOT NULL,\nTIMES_TRIGGERED NUMERIC(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nCRON_EXPRESSION VARCHAR(120) NOT NULL,\nTIME_ZONE_ID VARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nBLOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME VARCHAR(200) NOT NULL,\nCALENDAR BLOB NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE qrtz_paused_trigger_grps\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID VARCHAR(95) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nFIRED_TIME NUMERIC(13) NOT NULL,\nSCHED_TIME NUMERIC(13) NOT NULL,\nPRIORITY INTEGER NOT NULL,\nSTATE VARCHAR(16) NOT NULL,\nJOB_NAME VARCHAR(200) NULL,\nJOB_GROUP VARCHAR(200) NULL,\nIS_NONCONCURRENT BOOLEAN NULL,\nREQUESTS_RECOVERY BOOLEAN NULL,\nPRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nLAST_CHECKIN_TIME NUMERIC(13) NOT NULL,\nCHECKIN_INTERVAL NUMERIC(13) NOT NULL,\nPRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME VARCHAR(40) NOT NULL,\nPRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_hsqldb_old.sql",
    "content": "# \n# Thanks to  Joseph Wilkicki for submitting this file's contents\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.HSQLDBDelegate\n#\n# Some users report the need to change the fields\n# with datatype \"OTHER\" to datatype \"BINARY\" with\n# particular versions (e.g. 1.7.1) of HSQLDB\n#\n\nCREATE TABLE qrtz_job_details\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME LONGVARCHAR(80) NOT NULL,\nJOB_GROUP LONGVARCHAR(80) NOT NULL,\nDESCRIPTION LONGVARCHAR(120) NULL,\nJOB_CLASS_NAME LONGVARCHAR(128) NOT NULL,\nIS_DURABLE LONGVARCHAR(1) NOT NULL,\nIS_NONCONCURRENT LONGVARCHAR(1) NOT NULL,\nIS_UPDATE_DATA LONGVARCHAR(1) NOT NULL,\nREQUESTS_RECOVERY LONGVARCHAR(1) NOT NULL,\nJOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nJOB_NAME LONGVARCHAR(80) NOT NULL,\nJOB_GROUP LONGVARCHAR(80) NOT NULL,\nDESCRIPTION LONGVARCHAR(120) NULL,\nNEXT_FIRE_TIME NUMERIC(13) NULL,\nPREV_FIRE_TIME NUMERIC(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE LONGVARCHAR(16) NOT NULL,\nTRIGGER_TYPE LONGVARCHAR(8) NOT NULL,\nSTART_TIME NUMERIC(13) NOT NULL,\nEND_TIME NUMERIC(13) NULL,\nCALENDAR_NAME LONGVARCHAR(80) NULL,\nMISFIRE_INSTR NUMERIC(2) NULL,\nJOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_simple_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nREPEAT_COUNT NUMERIC(7) NOT NULL,\nREPEAT_INTERVAL NUMERIC(12) NOT NULL,\nTIMES_TRIGGERED NUMERIC(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nCRON_EXPRESSION LONGVARCHAR(120) NOT NULL,\nTIME_ZONE_ID LONGVARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME LONGVARCHAR(200) NOT NULL,\n    TRIGGER_GROUP LONGVARCHAR(200) NOT NULL,\n    STR_PROP_1 LONGVARCHAR(512) NULL,\n    STR_PROP_2 LONGVARCHAR(512) NULL,\n    STR_PROP_3 LONGVARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 LONGVARCHAR(1) NULL,\n    BOOL_PROP_2 LONGVARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nBLOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME LONGVARCHAR(80) NOT NULL,\nCALENDAR OTHER NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n); \n\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  LONGVARCHAR(80) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID LONGVARCHAR(95) NOT NULL,\n    TRIGGER_NAME LONGVARCHAR(80) NOT NULL,\n    TRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\n    INSTANCE_NAME LONGVARCHAR(80) NOT NULL,\n    FIRED_TIME NUMERIC(13) NOT NULL,\n    SCHED_TIME NUMERIC(13) NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE LONGVARCHAR(16) NOT NULL,\n    JOB_NAME LONGVARCHAR(80) NULL,\n    JOB_GROUP LONGVARCHAR(80) NULL,\n    IS_NONCONCURRENT LONGVARCHAR(1) NULL,\n    REQUESTS_RECOVERY LONGVARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME LONGVARCHAR(80) NOT NULL,\n    LAST_CHECKIN_TIME NUMERIC(13) NOT NULL,\n    CHECKIN_INTERVAL NUMERIC(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  LONGVARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_informix.sql",
    "content": "{ }\n{ Thanks to Keith Chew for submitting this. }\n{ }\n{ use the StdJDBCDelegate with Informix. }\n{ }\n{ note that Informix has a 18 character limit on the table name, so the prefix had to be shortened to \"q\" instead of \"qrtz_\" }\n\nCREATE TABLE qblob_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nBLOB_DATA byte in table\n);\n\nALTER TABLE qblob_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qcalendars (\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME varchar(80) NOT NULL,\nCALENDAR byte in table NOT NULL\n);\n\nALTER TABLE qcalendars\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,CALENDAR_NAME);\n\n\nCREATE TABLE qcron_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nCRON_EXPRESSION varchar(120) NOT NULL,\nTIME_ZONE_ID varchar(80)\n);\n\nALTER TABLE qcron_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qfired_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID varchar(95) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nINSTANCE_NAME varchar(80) NOT NULL,\nFIRED_TIME numeric(13) NOT NULL,\nSCHED_TIME numeric(13) NOT NULL,\nPRIORITY integer NOT NULL,\nSTATE varchar(16) NOT NULL,\nJOB_NAME varchar(80),\nJOB_GROUP varchar(80),\nIS_NONCONCURRENT varchar(1),\nREQUESTS_RECOVERY varchar(1) \n);\n\nALTER TABLE qfired_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,ENTRY_ID);\n\n\nCREATE TABLE qpaused_trigger_grps (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP  varchar(80) NOT NULL\n);\n\nALTER TABLE qpaused_trigger_grps\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP);\n\n\nCREATE TABLE qscheduler_state (\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME varchar(80) NOT NULL,\nLAST_CHECKIN_TIME numeric(13) NOT NULL,\nCHECKIN_INTERVAL numeric(13) NOT NULL\n);\n\nALTER TABLE qscheduler_state\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,INSTANCE_NAME);\n\n\nCREATE TABLE qlocks (\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME  varchar(40) NOT NULL\n);\n\nALTER TABLE qlocks\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,LOCK_NAME);\n\n\nCREATE TABLE qjob_details (\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME varchar(80) NOT NULL,\nJOB_GROUP varchar(80) NOT NULL,\nDESCRIPTION varchar(120),\nJOB_CLASS_NAME varchar(128) NOT NULL,\nIS_DURABLE varchar(1) NOT NULL,\nIS_NONCONCURRENT varchar(1) NOT NULL,\nIS_UPDATE_DATA varchar(1) NOT NULL,\nREQUESTS_RECOVERY varchar(1) NOT NULL,\nJOB_DATA byte in table\n);\n\nALTER TABLE qjob_details\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,JOB_NAME, JOB_GROUP);\n\n\nCREATE TABLE qsimple_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nREPEAT_COUNT numeric(7) NOT NULL,\nREPEAT_INTERVAL numeric(12) NOT NULL,\nTIMES_TRIGGERED numeric(10) NOT NULL\n);\n\nALTER TABLE qsimple_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qsimprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n);\n\nALTER TABLE qsimprop_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qtriggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nJOB_NAME varchar(80) NOT NULL,\nJOB_GROUP varchar(80) NOT NULL,\nDESCRIPTION varchar(120),\nNEXT_FIRE_TIME numeric(13),\nPREV_FIRE_TIME numeric(13),\nPRIORITY integer,\nTRIGGER_STATE varchar(16) NOT NULL,\nTRIGGER_TYPE varchar(8) NOT NULL,\nSTART_TIME numeric(13) NOT NULL,\nEND_TIME numeric(13),\nCALENDAR_NAME varchar(80),\nMISFIRE_INSTR numeric(2),\nJOB_DATA byte in table\n);\n\nALTER TABLE qtriggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nALTER TABLE qblob_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\n\nALTER TABLE qcron_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\n\nALTER TABLE qsimple_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\nALTER TABLE qsimprop_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\nALTER TABLE qtriggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,JOB_NAME, JOB_GROUP)\nREFERENCES qjob_details; \n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_mysql.sql",
    "content": "#\n# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar\n#\n# PLEASE consider using mysql with innodb tables to avoid locking issues\n#\n# In your Quartz properties file, you'll need to set\n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,\n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT(13) NULL,\n    PREV_FIRE_TIME BIGINT(13) NULL,\n    PRIORITY INTEGER NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT(13) NOT NULL,\n    END_TIME BIGINT(13) NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR SMALLINT(2) NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT BIGINT(7) NOT NULL,\n    REPEAT_INTERVAL BIGINT(12) NOT NULL,\n    TIMES_TRIGGERED BIGINT(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(200) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    CALENDAR BLOB NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME BIGINT(13) NOT NULL,\n    SCHED_TIME BIGINT(13) NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT VARCHAR(1) NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,\n    CHECKIN_INTERVAL BIGINT(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql",
    "content": "#\n# In your Quartz properties file, you'll need to set\n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n#\n# By: Ron Cordell - roncordell\n#  I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME VARCHAR(190) NOT NULL,\nJOB_GROUP VARCHAR(190) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nJOB_CLASS_NAME VARCHAR(250) NOT NULL,\nIS_DURABLE VARCHAR(1) NOT NULL,\nIS_NONCONCURRENT VARCHAR(1) NOT NULL,\nIS_UPDATE_DATA VARCHAR(1) NOT NULL,\nREQUESTS_RECOVERY VARCHAR(1) NOT NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(190) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nJOB_NAME VARCHAR(190) NOT NULL,\nJOB_GROUP VARCHAR(190) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nNEXT_FIRE_TIME BIGINT(13) NULL,\nPREV_FIRE_TIME BIGINT(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE VARCHAR(16) NOT NULL,\nTRIGGER_TYPE VARCHAR(8) NOT NULL,\nSTART_TIME BIGINT(13) NOT NULL,\nEND_TIME BIGINT(13) NULL,\nCALENDAR_NAME VARCHAR(190) NULL,\nMISFIRE_INSTR SMALLINT(2) NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(190) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nREPEAT_COUNT BIGINT(7) NOT NULL,\nREPEAT_INTERVAL BIGINT(12) NOT NULL,\nTIMES_TRIGGERED BIGINT(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(190) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nCRON_EXPRESSION VARCHAR(120) NOT NULL,\nTIME_ZONE_ID VARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(190) NOT NULL,\n    TRIGGER_GROUP VARCHAR(190) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(190) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nBLOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nINDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_CALENDARS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME VARCHAR(190) NOT NULL,\nCALENDAR BLOB NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID VARCHAR(95) NOT NULL,\nTRIGGER_NAME VARCHAR(190) NOT NULL,\nTRIGGER_GROUP VARCHAR(190) NOT NULL,\nINSTANCE_NAME VARCHAR(190) NOT NULL,\nFIRED_TIME BIGINT(13) NOT NULL,\nSCHED_TIME BIGINT(13) NOT NULL,\nPRIORITY INTEGER NOT NULL,\nSTATE VARCHAR(16) NOT NULL,\nJOB_NAME VARCHAR(190) NULL,\nJOB_GROUP VARCHAR(190) NULL,\nIS_NONCONCURRENT VARCHAR(1) NULL,\nREQUESTS_RECOVERY VARCHAR(1) NULL,\nPRIMARY KEY (SCHED_NAME,ENTRY_ID))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME VARCHAR(190) NOT NULL,\nLAST_CHECKIN_TIME BIGINT(13) NOT NULL,\nCHECKIN_INTERVAL BIGINT(13) NOT NULL,\nPRIMARY KEY (SCHED_NAME,INSTANCE_NAME))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_LOCKS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME VARCHAR(40) NOT NULL,\nPRIMARY KEY (SCHED_NAME,LOCK_NAME))\nENGINE=InnoDB;\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);\n\nCREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_oracle.sql",
    "content": "--\n-- A hint submitted by a user: Oracle DB MUST be created as \"shared\" and the \n-- job_queue_processes parameter  must be greater than 2\n-- However, these settings are pretty much standard after any\n-- Oracle install, so most users need not worry about this.\n--\n-- Many other users (including the primary author of Quartz) have had success\n-- running in dedicated mode, so only consider the above as a hint ;-)\n--\n\ndelete from qrtz_fired_triggers;\ndelete from qrtz_simple_triggers;\ndelete from qrtz_simprop_triggers;\ndelete from qrtz_cron_triggers;\ndelete from qrtz_blob_triggers;\ndelete from qrtz_triggers;\ndelete from qrtz_job_details;\ndelete from qrtz_calendars;\ndelete from qrtz_paused_trigger_grps;\ndelete from qrtz_locks;\ndelete from qrtz_scheduler_state;\n\ndrop table qrtz_calendars;\ndrop table qrtz_fired_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_locks;\ndrop table qrtz_scheduler_state;\n\n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL,\n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    JOB_CLASS_NAME   VARCHAR2(250) NOT NULL, \n    IS_DURABLE VARCHAR2(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR2(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR2(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL, \n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    NEXT_FIRE_TIME NUMBER(13) NULL,\n    PREV_FIRE_TIME NUMBER(13) NULL,\n    PRIORITY NUMBER(13) NULL,\n    TRIGGER_STATE VARCHAR2(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR2(8) NOT NULL,\n    START_TIME NUMBER(13) NOT NULL,\n    END_TIME NUMBER(13) NULL,\n    CALENDAR_NAME VARCHAR2(200) NULL,\n    MISFIRE_INSTR NUMBER(2) NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n      REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    REPEAT_COUNT NUMBER(7) NOT NULL,\n    REPEAT_INTERVAL NUMBER(12) NOT NULL,\n    TIMES_TRIGGERED NUMBER(10) NOT NULL,\n    CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR2(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR2(80),\n    CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    STR_PROP_1 VARCHAR2(512) NULL,\n    STR_PROP_2 VARCHAR2(512) NULL,\n    STR_PROP_3 VARCHAR2(512) NULL,\n    INT_PROP_1 NUMBER(10) NULL,\n    INT_PROP_2 NUMBER(10) NULL,\n    LONG_PROP_1 NUMBER(13) NULL,\n    LONG_PROP_2 NUMBER(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR2(1) NULL,\n    BOOL_PROP_2 VARCHAR2(1) NULL,\n    CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR2(200) NOT NULL, \n    CALENDAR BLOB NOT NULL,\n    CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR2(200) NOT NULL, \n    CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    ENTRY_ID VARCHAR2(95) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    FIRED_TIME NUMBER(13) NOT NULL,\n    SCHED_TIME NUMBER(13) NOT NULL,\n    PRIORITY NUMBER(13) NOT NULL,\n    STATE VARCHAR2(16) NOT NULL,\n    JOB_NAME VARCHAR2(200) NULL,\n    JOB_GROUP VARCHAR2(200) NULL,\n    IS_NONCONCURRENT VARCHAR2(1) NULL,\n    REQUESTS_RECOVERY VARCHAR2(1) NULL,\n    CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,\n    CHECKIN_INTERVAL NUMBER(13) NOT NULL,\n    CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    LOCK_NAME  VARCHAR2(40) NOT NULL, \n    CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncreate index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);\n\ncreate index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);\ncreate index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\ncreate index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\ncreate index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);\ncreate index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);\n\n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_oracle23.sql",
    "content": "--\n-- A hint submitted by a user: Oracle DB MUST be created as \"shared\" and the \n-- job_queue_processes parameter  must be greater than 2\n-- However, these settings are pretty much standard after any\n-- Oracle install, so most users need not worry about this.\n--\n-- Many other users (including the primary author of Quartz) have had success\n-- running in dedicated mode, so only consider the above as a hint ;-)\n--\n\ndelete from qrtz_fired_triggers;\ndelete from qrtz_simple_triggers;\ndelete from qrtz_simprop_triggers;\ndelete from qrtz_cron_triggers;\ndelete from qrtz_blob_triggers;\ndelete from qrtz_triggers;\ndelete from qrtz_job_details;\ndelete from qrtz_calendars;\ndelete from qrtz_paused_trigger_grps;\ndelete from qrtz_locks;\ndelete from qrtz_scheduler_state;\n\ndrop table qrtz_calendars;\ndrop table qrtz_fired_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_locks;\ndrop table qrtz_scheduler_state;\n\n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL,\n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    JOB_CLASS_NAME   VARCHAR2(250) NOT NULL, \n    IS_DURABLE BOOLEAN NOT NULL,\n    IS_NONCONCURRENT BOOLEAN NOT NULL,\n    IS_UPDATE_DATA BOOLEAN NOT NULL,\n    REQUESTS_RECOVERY BOOLEAN NOT NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL, \n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    NEXT_FIRE_TIME NUMBER(13) NULL,\n    PREV_FIRE_TIME NUMBER(13) NULL,\n    PRIORITY NUMBER(13) NULL,\n    TRIGGER_STATE VARCHAR2(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR2(8) NOT NULL,\n    START_TIME NUMBER(13) NOT NULL,\n    END_TIME NUMBER(13) NULL,\n    CALENDAR_NAME VARCHAR2(200) NULL,\n    MISFIRE_INSTR NUMBER(2) NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n      REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    REPEAT_COUNT NUMBER(7) NOT NULL,\n    REPEAT_INTERVAL NUMBER(12) NOT NULL,\n    TIMES_TRIGGERED NUMBER(10) NOT NULL,\n    CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR2(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR2(80),\n    CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    STR_PROP_1 VARCHAR2(512) NULL,\n    STR_PROP_2 VARCHAR2(512) NULL,\n    STR_PROP_3 VARCHAR2(512) NULL,\n    INT_PROP_1 NUMBER(10) NULL,\n    INT_PROP_2 NUMBER(10) NULL,\n    LONG_PROP_1 NUMBER(13) NULL,\n    LONG_PROP_2 NUMBER(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n    CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR2(200) NOT NULL, \n    CALENDAR BLOB NOT NULL,\n    CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR2(200) NOT NULL, \n    CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    ENTRY_ID VARCHAR2(95) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    FIRED_TIME NUMBER(13) NOT NULL,\n    SCHED_TIME NUMBER(13) NOT NULL,\n    PRIORITY NUMBER(13) NOT NULL,\n    STATE VARCHAR2(16) NOT NULL,\n    JOB_NAME VARCHAR2(200) NULL,\n    JOB_GROUP VARCHAR2(200) NULL,\n    IS_NONCONCURRENT BOOLEAN NULL,\n    REQUESTS_RECOVERY BOOLEAN NULL,\n    CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,\n    CHECKIN_INTERVAL NUMBER(13) NOT NULL,\n    CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    LOCK_NAME  VARCHAR2(40) NOT NULL, \n    CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncreate index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);\n\ncreate index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);\ncreate index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\ncreate index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\ncreate index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);\ncreate index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_pointbase.sql",
    "content": "#\n# Thanks to Gregg Freeman\n#\n#\n# ...you may want to change defined the size of the \"blob\" columns before\n# creating the tables (particularly for the qrtz_job_details.job_data column), \n# if you will be storing large amounts of data in them\n#\n#\ndelete from qrtz_fired_triggers;\ndelete from qrtz_simple_triggers;\ndelete from qrtz_simprop_triggers;\ndelete from qrtz_cron_triggers;\ndelete from qrtz_blob_triggers;\ndelete from qrtz_triggers;\ndelete from qrtz_job_details;\ndelete from qrtz_calendars;\ndelete from qrtz_paused_trigger_grps;\ndelete from qrtz_locks;\ndelete from qrtz_scheduler_state;\n\ndrop table qrtz_calendars;\ndrop table qrtz_fired_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_locks;\ndrop table qrtz_scheduler_state;\n \n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR2(80) NOT NULL,\n    JOB_GROUP VARCHAR2(80) NOT NULL,\n    DESCRIPTION VARCHAR2(120) NULL,\n    JOB_CLASS_NAME   VARCHAR2(128) NOT NULL, \n    IS_DURABLE BOOLEAN NOT NULL,\n    IS_NONCONCURRENT BOOLEAN NOT NULL,\n    IS_UPDATE_DATA BOOLEAN NOT NULL,\n    REQUESTS_RECOVERY BOOLEAN NOT NULL,\n    JOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    JOB_NAME  VARCHAR2(80) NOT NULL, \n    JOB_GROUP VARCHAR2(80) NOT NULL,\n    DESCRIPTION VARCHAR2(120) NULL,\n    NEXT_FIRE_TIME NUMBER(13) NULL,\n    PREV_FIRE_TIME NUMBER(13) NULL,\n    PRIORITY NUMBER(13) NULL,\n    TRIGGER_STATE VARCHAR2(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR2(8) NOT NULL,\n    START_TIME NUMBER(13) NOT NULL,\n    END_TIME NUMBER(13) NULL,\n    CALENDAR_NAME VARCHAR2(80) NULL,\n    MISFIRE_INSTR NUMBER(2) NULL,\n    JOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n\tREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    REPEAT_COUNT NUMBER(7) NOT NULL,\n    REPEAT_INTERVAL NUMBER(12) NOT NULL,\n    TIMES_TRIGGERED NUMBER(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMBER(10) NULL,\n    INT_PROP_2 NUMBER(10) NULL,\n    LONG_PROP_1 NUMBER(13) NULL,\n    LONG_PROP_2 NUMBER(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    CRON_EXPRESSION VARCHAR2(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR2(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    BLOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR2(80) NOT NULL, \n    CALENDAR BLOB(4K) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR2(80) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR2(95) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    INSTANCE_NAME VARCHAR2(80) NOT NULL,\n    FIRED_TIME NUMBER(13) NOT NULL,\n    SCHED_TIME NUMBER(13) NOT NULL,\n    PRIORITY NUMBER(13) NOT NULL,\n    STATE VARCHAR2(16) NOT NULL,\n    JOB_NAME VARCHAR2(80) NULL,\n    JOB_GROUP VARCHAR2(80) NULL,\n    IS_NONCONCURRENT BOOLEAN NULL,\n    REQUESTS_RECOVERY BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR2(80) NOT NULL,\n    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,\n    CHECKIN_INTERVAL NUMBER(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR2(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_postgres.sql",
    "content": "-- Thanks to Patrick Lightbody for submitting this...\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  JOB_NAME          VARCHAR(200) NOT NULL,\n  JOB_GROUP         VARCHAR(200) NOT NULL,\n  DESCRIPTION       VARCHAR(250) NULL,\n  JOB_CLASS_NAME    VARCHAR(250) NOT NULL,\n  IS_DURABLE        BOOL         NOT NULL,\n  IS_NONCONCURRENT  BOOL         NOT NULL,\n  IS_UPDATE_DATA    BOOL         NOT NULL,\n  REQUESTS_RECOVERY BOOL         NOT NULL,\n  JOB_DATA          BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n(\n  SCHED_NAME     VARCHAR(120) NOT NULL,\n  TRIGGER_NAME   VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP  VARCHAR(200) NOT NULL,\n  JOB_NAME       VARCHAR(200) NOT NULL,\n  JOB_GROUP      VARCHAR(200) NOT NULL,\n  DESCRIPTION    VARCHAR(250) NULL,\n  NEXT_FIRE_TIME BIGINT       NULL,\n  PREV_FIRE_TIME BIGINT       NULL,\n  PRIORITY       INTEGER      NULL,\n  TRIGGER_STATE  VARCHAR(16)  NOT NULL,\n  TRIGGER_TYPE   VARCHAR(8)   NOT NULL,\n  START_TIME     BIGINT       NOT NULL,\n  END_TIME       BIGINT       NULL,\n  CALENDAR_NAME  VARCHAR(200) NULL,\n  MISFIRE_INSTR  SMALLINT     NULL,\n  JOB_DATA       BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)\n  REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n(\n  SCHED_NAME      VARCHAR(120) NOT NULL,\n  TRIGGER_NAME    VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n  REPEAT_COUNT    BIGINT       NOT NULL,\n  REPEAT_INTERVAL BIGINT       NOT NULL,\n  TIMES_TRIGGERED BIGINT       NOT NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n(\n  SCHED_NAME      VARCHAR(120) NOT NULL,\n  TRIGGER_NAME    VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP   VARCHAR(200) NOT NULL,\n  CRON_EXPRESSION VARCHAR(120) NOT NULL,\n  TIME_ZONE_ID    VARCHAR(80),\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n(\n  SCHED_NAME    VARCHAR(120)   NOT NULL,\n  TRIGGER_NAME  VARCHAR(200)   NOT NULL,\n  TRIGGER_GROUP VARCHAR(200)   NOT NULL,\n  STR_PROP_1    VARCHAR(512)   NULL,\n  STR_PROP_2    VARCHAR(512)   NULL,\n  STR_PROP_3    VARCHAR(512)   NULL,\n  INT_PROP_1    INT            NULL,\n  INT_PROP_2    INT            NULL,\n  LONG_PROP_1   BIGINT         NULL,\n  LONG_PROP_2   BIGINT         NULL,\n  DEC_PROP_1    NUMERIC(13, 4) NULL,\n  DEC_PROP_2    NUMERIC(13, 4) NULL,\n  BOOL_PROP_1   BOOL           NULL,\n  BOOL_PROP_2   BOOL           NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  TRIGGER_NAME  VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP VARCHAR(200) NOT NULL,\n  BLOB_DATA     BYTEA        NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),\n  FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n  REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR(200) NOT NULL,\n  CALENDAR      BYTEA        NOT NULL,\n  PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)\n);\n\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n(\n  SCHED_NAME    VARCHAR(120) NOT NULL,\n  TRIGGER_GROUP VARCHAR(200) NOT NULL,\n  PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  ENTRY_ID          VARCHAR(95)  NOT NULL,\n  TRIGGER_NAME      VARCHAR(200) NOT NULL,\n  TRIGGER_GROUP     VARCHAR(200) NOT NULL,\n  INSTANCE_NAME     VARCHAR(200) NOT NULL,\n  FIRED_TIME        BIGINT       NOT NULL,\n  SCHED_TIME        BIGINT       NOT NULL,\n  PRIORITY          INTEGER      NOT NULL,\n  STATE             VARCHAR(16)  NOT NULL,\n  JOB_NAME          VARCHAR(200) NULL,\n  JOB_GROUP         VARCHAR(200) NULL,\n  IS_NONCONCURRENT  BOOL         NULL,\n  REQUESTS_RECOVERY BOOL         NULL,\n  PRIMARY KEY (SCHED_NAME, ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n(\n  SCHED_NAME        VARCHAR(120) NOT NULL,\n  INSTANCE_NAME     VARCHAR(200) NOT NULL,\n  LAST_CHECKIN_TIME BIGINT       NOT NULL,\n  CHECKIN_INTERVAL  BIGINT       NOT NULL,\n  PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n(\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  LOCK_NAME  VARCHAR(40)  NOT NULL,\n  PRIMARY KEY (SCHED_NAME, LOCK_NAME)\n);\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY\n  ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP\n  ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);\n\nCREATE INDEX IDX_QRTZ_T_J\n  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_JG\n  ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C\n  ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME\n  ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST\n  ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP\n  ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG\n  ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);\n\n\nCOMMIT;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_sapdb.sql",
    "content": "#\n# Thanks to Andrew Perepelytsya for submitting this file.\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n\nCREATE TABLE QRTZ_JOB_DETAILS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME VARCHAR(128) NOT NULL, \n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL, \n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME FIXED(13) NULL,\n    PREV_FIRE_TIME FIXED(13) NULL,\n    PRIORITY FIXED(13) NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME FIXED(13) NOT NULL,\n    END_TIME FIXED(13) NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR FIXED(2) NULL,\n    JOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT FIXED(7) NOT NULL,\n    REPEAT_INTERVAL FIXED(12) NOT NULL,\n    TIMES_TRIGGERED FIXED(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 FIXED(10) NULL,\n    INT_PROP_2 FIXED(10) NULL,\n    LONG_PROP_1 FIXED(13) NULL,\n    LONG_PROP_2 FIXED(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    CALENDAR LONG BYTE NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME FIXED(13) NOT NULL,\n    SCHED_TIME FIXED(13) NOT NULL,\n    PRIORITY FIXED(13) NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT VARCHAR(1) NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME FIXED(13) NOT NULL,\n    CHECKIN_INTERVAL FIXED(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\ncommit;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_solid.sql",
    "content": "\nDROP TABLE qrtz_locks;\nDROP TABLE qrtz_scheduler_state;\nDROP TABLE qrtz_fired_triggers;\nDROP TABLE qrtz_paused_trigger_grps;\nDROP TABLE qrtz_calendars;\nDROP TABLE qrtz_blob_triggers;\nDROP TABLE qrtz_cron_triggers;\nDROP TABLE qrtz_simple_triggers;\nDROP TABLE qrtz_simprop_triggers;\nDROP TABLE qrtz_triggers;\nDROP TABLE qrtz_job_details;\n\ncreate table qrtz_job_details (\n    sched_name varchar(120) not null,\n\tjob_name varchar(80) not null,\n\tjob_group varchar(80) not null,\n\tdescription varchar(120) ,\n\tjob_class_name varchar(128) not null,\n\tis_durable varchar(5) not null,\n    is_nonconcurrent varchar(5) not null,\n    is_update_data varchar(5) not null,\n\trequests_recovery varchar(5) not null,\n\tjob_data long varbinary,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tjob_name varchar(80) not null,\n\tjob_group varchar(80) not null,\n\tdescription varchar(120) ,\n\tnext_fire_time numeric(13),\n\tprev_fire_time numeric(13),\n\tpriority integer,\n\ttrigger_state varchar(16) not null,\n\ttrigger_type varchar(8) not null,\n\tstart_time numeric(13) not null,\n\tend_time numeric(13),\n\tcalendar_name varchar(80),\n\tmisfire_instr smallint,\n\tjob_data long varbinary,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\trepeat_count numeric(13) not null,\n\trepeat_interval numeric(13) not null,\n\ttimes_triggered numeric(13) not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    trigger_name VARCHAR(200) NOT NULL,\n    trigger_group VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INTEGER NULL,\n    INT_PROP_2 INTEGER NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(5) NULL,\n    BOOL_PROP_2 VARCHAR(5) NULL,\nPRIMARY KEY (sched_name,trigger_name,trigger_group),\nFOREIGN KEY (sched_name,trigger_name,trigger_group) REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\n\ncreate table qrtz_cron_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tcron_expression varchar(120) not null,\n\ttime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tblob_data long varbinary ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n    sched_name varchar(120) not null,\n\tcalendar_name varchar(80) not null,\n\tcalendar long varbinary not null,\nprimary key (sched_name,calendar_name)\n); \n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group  varchar(80) not null, \nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\n    sched_name varchar(120) not null,\n\tentry_id varchar(95) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tinstance_name varchar(80) not null,\n\tfired_time numeric(13) not null,\n\tsched_time numeric(13) not null,\n\tpriority integer not null,\n\tstate varchar(16) not null,\n\tjob_name varchar(80) null,\n\tjob_group varchar(80) null,\n\tis_nonconcurrent varchar(5) null,\n\trequests_recovery varchar(5) null,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state \n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(80) not null,\n    last_checkin_time numeric(13) not null,\n    checkin_interval numeric(13) not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \nprimary key (sched_name,lock_name)\n);\n\ncommit work;\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_sqlServer.sql",
    "content": "--# thanks to George Papastamatopoulos for submitting this ... and Marko Lahma for\n--# updating it.\n--#\n--# In your Quartz properties file, you'll need to set \n--# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate\n--#\n--# you shouse enter your DB instance's name on the next line in place of \"enter_db_name_here\"\n--#\n--#\n--# From a helpful (but anonymous) Quartz user:\n--#\n--# Regarding this error message:  \n--#\n--#     [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.\n--#\n--#\n--#     I added \"SelectMethod=cursor;\" to my Connection URL in the config file. \n--#     It Seems to work, hopefully no side effects.\n--#\n--#\t\texample:\n--#\t\t\"jdbc:microsoft:sqlserver://dbmachine:1433;SelectMethod=cursor\"; \n--#\n--# Another user has pointed out that you will probably need to use the \n--# JTDS driver\n--#\n\nUSE [enter_db_name_here]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] DROP CONSTRAINT FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_CALENDARS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_CRON_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SCHEDULER_STATE]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_LOCKS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_JOB_DETAILS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_TRIGGERS]\nGO\n\nCREATE TABLE [dbo].[QRTZ_CALENDARS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [CALENDAR_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [CALENDAR] [VARBINARY] (max) NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [CRON_EXPRESSION] [NVARCHAR] (120)  NOT NULL ,\n  [TIME_ZONE_ID] [NVARCHAR] (80)\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [ENTRY_ID] [NVARCHAR] (95)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [INSTANCE_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [FIRED_TIME] [BIGINT] NOT NULL ,\n  [SCHED_TIME] [BIGINT] NOT NULL ,\n  [PRIORITY] [INTEGER] NOT NULL ,\n  [STATE] [NVARCHAR] (16)  NOT NULL,\n  [JOB_NAME] [NVARCHAR] (200)  NULL ,\n  [JOB_GROUP] [NVARCHAR] (200)  NULL ,\n  [IS_NONCONCURRENT] [NVARCHAR] (1)  NULL ,\n  [REQUESTS_RECOVERY] [NVARCHAR] (1)  NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [INSTANCE_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [LAST_CHECKIN_TIME] [BIGINT] NOT NULL ,\n  [CHECKIN_INTERVAL] [BIGINT] NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_LOCKS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [LOCK_NAME] [NVARCHAR] (40)  NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_JOB_DETAILS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [JOB_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [JOB_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [DESCRIPTION] [NVARCHAR] (250) NULL ,\n  [JOB_CLASS_NAME] [NVARCHAR] (250)  NOT NULL ,\n  [IS_DURABLE] [NVARCHAR] (1)  NOT NULL ,\n  [IS_NONCONCURRENT] [NVARCHAR] (1)  NOT NULL ,\n  [IS_UPDATE_DATA] [NVARCHAR] (1)  NOT NULL ,\n  [REQUESTS_RECOVERY] [NVARCHAR] (1)  NOT NULL ,\n  [JOB_DATA] [VARBINARY] (max) NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [REPEAT_COUNT] [BIGINT] NOT NULL ,\n  [REPEAT_INTERVAL] [BIGINT] NOT NULL ,\n  [TIMES_TRIGGERED] [BIGINT] NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [STR_PROP_1] [NVARCHAR] (512) NULL,\n  [STR_PROP_2] [NVARCHAR] (512) NULL,\n  [STR_PROP_3] [NVARCHAR] (512) NULL,\n  [INT_PROP_1] [INT] NULL,\n  [INT_PROP_2] [INT] NULL,\n  [LONG_PROP_1] [BIGINT] NULL,\n  [LONG_PROP_2] [BIGINT] NULL,\n  [DEC_PROP_1] [NUMERIC] (13,4) NULL,\n  [DEC_PROP_2] [NUMERIC] (13,4) NULL,\n  [BOOL_PROP_1] [NVARCHAR] (1) NULL,\n  [BOOL_PROP_2] [NVARCHAR] (1) NULL,\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [BLOB_DATA] [VARBINARY] (max) NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_TRIGGERS] (\n  [SCHED_NAME] [NVARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [JOB_NAME] [NVARCHAR] (200)  NOT NULL ,\n  [JOB_GROUP] [NVARCHAR] (200)  NOT NULL ,\n  [DESCRIPTION] [NVARCHAR] (250) NULL ,\n  [NEXT_FIRE_TIME] [BIGINT] NULL ,\n  [PREV_FIRE_TIME] [BIGINT] NULL ,\n  [PRIORITY] [INTEGER] NULL ,\n  [TRIGGER_STATE] [NVARCHAR] (16)  NOT NULL ,\n  [TRIGGER_TYPE] [NVARCHAR] (8)  NOT NULL ,\n  [START_TIME] [BIGINT] NOT NULL ,\n  [END_TIME] [BIGINT] NULL ,\n  [CALENDAR_NAME] [NVARCHAR] (200)  NULL ,\n  [MISFIRE_INSTR] [SMALLINT] NULL ,\n  [JOB_DATA] [VARBINARY] (max) NULL\n) ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [CALENDAR_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [ENTRY_ID]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [INSTANCE_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [LOCK_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  ) REFERENCES [dbo].[QRTZ_JOB_DETAILS] (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  )\nGO\n\nCREATE NONCLUSTERED INDEX [IX_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] ON [dbo].[QRTZ_CRON_TRIGGERS]\n  (\n    [SCHED_NAME] ASC,\n    [TRIGGER_NAME] ASC,\n    [TRIGGER_GROUP] ASC\n  ) WITH (\n    PAD_INDEX  = OFF,\n    STATISTICS_NORECOMPUTE  = OFF,\n    SORT_IN_TEMPDB = OFF,\n    IGNORE_DUP_KEY = OFF,\n    DROP_EXISTING = OFF,\n    ONLINE = OFF,\n    ALLOW_ROW_LOCKS  = ON,\n    ALLOW_PAGE_LOCKS  = ON\n  ) ON [PRIMARY]\nGO\n\nCREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] ON [dbo].[QRTZ_SIMPLE_TRIGGERS]\n  (\n    [SCHED_NAME] ASC,\n    [TRIGGER_NAME] ASC,\n    [TRIGGER_GROUP] ASC\n  ) WITH (\n    PAD_INDEX  = OFF,\n    STATISTICS_NORECOMPUTE  = OFF,\n    SORT_IN_TEMPDB = OFF,\n    IGNORE_DUP_KEY = OFF,\n    DROP_EXISTING = OFF,\n    ONLINE = OFF,\n    ALLOW_ROW_LOCKS  = ON,\n    ALLOW_PAGE_LOCKS  = ON\n  ) ON [PRIMARY]\nGO\n\nCREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] ON [dbo].[QRTZ_SIMPROP_TRIGGERS]\n  (\n    [SCHED_NAME] ASC,\n    [TRIGGER_NAME] ASC,\n    [TRIGGER_GROUP] ASC\n  ) WITH (\n    PAD_INDEX  = OFF,\n    STATISTICS_NORECOMPUTE  = OFF,\n    SORT_IN_TEMPDB = OFF,\n    IGNORE_DUP_KEY = OFF,\n    DROP_EXISTING = OFF,\n    ONLINE = OFF,\n    ALLOW_ROW_LOCKS  = ON,\n    ALLOW_PAGE_LOCKS  = ON\n  ) ON [PRIMARY]\nGO\n\nCREATE NONCLUSTERED INDEX [IX_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] ON [dbo].[QRTZ_TRIGGERS]\n  (\n    [SCHED_NAME] ASC,\n    [TRIGGER_NAME] ASC,\n    [TRIGGER_GROUP] ASC\n  ) WITH (\n    PAD_INDEX  = OFF,\n    STATISTICS_NORECOMPUTE  = OFF,\n    SORT_IN_TEMPDB = OFF,\n    IGNORE_DUP_KEY = OFF,\n    DROP_EXISTING = OFF,\n    ONLINE = OFF,\n    ALLOW_ROW_LOCKS  = ON,\n    ALLOW_PAGE_LOCKS  = ON\n  ) ON [PRIMARY]\nGO\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_sybase.sql",
    "content": "/*==============================================================================================*/\n/* Quartz database tables creation script for Sybase ASE 12.5 */\n/* Written by Pertti Laiho (email: pertti.laiho@deio.net), 9th May 2003 */\n/* */\n/* Compatible with Quartz version 1.1.2 */\n/* */\n/* Sybase ASE works ok with the SybaseDelegate delegate class. That means in your Quartz properties */\n/* file, you'll need to set: */\n/* org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.SybaseDelegate */\n/*==============================================================================================*/\n\nuse your_db_name_here\ngo\n\n/*==============================================================================*/\n/* Clear all tables: */\n/*==============================================================================*/\n\nIF OBJECT_ID('QRTZ_FIRED_TRIGGERS') IS NOT NULL \ndelete from QRTZ_FIRED_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_PAUSED_TRIGGER_GRPS') IS NOT NULL \ndelete from QRTZ_PAUSED_TRIGGER_GRPS\ngo\nIF OBJECT_ID('QRTZ_SCHEDULER_STATE') IS NOT NULL \ndelete from QRTZ_SCHEDULER_STATE\ngo\nIF OBJECT_ID('QRTZ_LOCKS') IS NOT NULL \ndelete from QRTZ_LOCKS\ngo\nIF OBJECT_ID('QRTZ_SIMPLE_TRIGGERS') IS NOT NULL \ndelete from QRTZ_SIMPLE_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_SIMPROP_TRIGGERS') IS NOT NULL \ndelete from QRTZ_SIMPROP_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_CRON_TRIGGERS') IS NOT NULL \ndelete from QRTZ_CRON_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_BLOB_TRIGGERS') IS NOT NULL \ndelete from QRTZ_BLOB_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_TRIGGERS') IS NOT NULL \ndelete from QRTZ_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_JOB_DETAILS') IS NOT NULL \ndelete from QRTZ_JOB_DETAILS\ngo\nIF OBJECT_ID('QRTZ_CALENDARS') IS NOT NULL \ndelete from QRTZ_CALENDARS\ngo\n\n/*==============================================================================*/\n/* Drop constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_TRIGGERS\ndrop constraint FK_triggers_job_details\ngo\n\nalter table QRTZ_CRON_TRIGGERS\ndrop constraint FK_cron_triggers_triggers\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\ndrop constraint FK_simple_triggers_triggers\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\ndrop constraint FK_simprop_triggers_triggers\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\ndrop constraint FK_blob_triggers_triggers\ngo\n\n/*==============================================================================*/\n/* Drop tables: */\n/*==============================================================================*/\n\ndrop table QRTZ_FIRED_TRIGGERS\ngo\ndrop table QRTZ_PAUSED_TRIGGER_GRPS\ngo\ndrop table QRTZ_SCHEDULER_STATE\ngo\ndrop table QRTZ_LOCKS\ngo\ndrop table QRTZ_SIMPLE_TRIGGERS\ngo\ndrop table QRTZ_SIMPROP_TRIGGERS\ngo\ndrop table QRTZ_CRON_TRIGGERS\ngo\ndrop table QRTZ_BLOB_TRIGGERS\ngo\ndrop table QRTZ_TRIGGERS\ngo\ndrop table QRTZ_JOB_DETAILS\ngo\ndrop table QRTZ_CALENDARS\ngo\n\n/*==============================================================================*/\n/* Create tables: */\n/*==============================================================================*/\n\ncreate table QRTZ_CALENDARS (\nSCHED_NAME varchar(120) not null,\nCALENDAR_NAME varchar(200) not null,\nCALENDAR image not null\n)\ngo\n\ncreate table QRTZ_CRON_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(200) not null,\nTRIGGER_GROUP varchar(200) not null,\nCRON_EXPRESSION varchar(120) not null,\nTIME_ZONE_ID varchar(80) null,\n)\ngo\n\ncreate table QRTZ_PAUSED_TRIGGER_GRPS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_GROUP  varchar(200) not null, \n)\ngo\n\ncreate table QRTZ_FIRED_TRIGGERS(\nSCHED_NAME varchar(120) not null,\nENTRY_ID varchar(95) not null,\nTRIGGER_NAME varchar(200) not null,\nTRIGGER_GROUP varchar(200) not null,\nINSTANCE_NAME varchar(200) not null,\nFIRED_TIME numeric(13,0) not null,\nSCHED_TIME numeric(13,0) not null,\nPRIORITY int not null,\nSTATE varchar(16) not null,\nJOB_NAME varchar(200) null,\nJOB_GROUP varchar(200) null,\nIS_NONCONCURRENT bit not null,\nREQUESTS_RECOVERY bit not null,\n)\ngo\n\ncreate table QRTZ_SCHEDULER_STATE (\nSCHED_NAME varchar(120) not null,\nINSTANCE_NAME varchar(200) not null,\nLAST_CHECKIN_TIME numeric(13,0) not null,\nCHECKIN_INTERVAL numeric(13,0) not null,\n)\ngo\n\ncreate table QRTZ_LOCKS (\nSCHED_NAME varchar(120) not null,\nLOCK_NAME  varchar(40) not null, \n)\ngo\n\n\ncreate table QRTZ_JOB_DETAILS (\nSCHED_NAME varchar(120) not null,\nJOB_NAME varchar(200) not null,\nJOB_GROUP varchar(200) not null,\nDESCRIPTION varchar(250) null,\nJOB_CLASS_NAME varchar(250) not null,\nIS_DURABLE bit not null,\nIS_NONCONCURRENT bit not null,\nIS_UPDATE_DATA bit not null,\nREQUESTS_RECOVERY bit not null,\nJOB_DATA image null\n)\ngo\n\ncreate table QRTZ_SIMPLE_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(200) not null,\nTRIGGER_GROUP varchar(200) not null,\nREPEAT_COUNT numeric(13,0) not null,\nREPEAT_INTERVAL numeric(13,0) not null,\nTIMES_TRIGGERED numeric(13,0) not null\n)\ngo\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 NUMERIC(13,0) NULL,\n    LONG_PROP_2 NUMERIC(13,0) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 bit NOT NULL,\n    BOOL_PROP_2 bit NOT NULL\n)\ngo\n\ncreate table QRTZ_BLOB_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(200) not null,\nTRIGGER_GROUP varchar(200) not null,\nBLOB_DATA image null\n)\ngo\n\ncreate table QRTZ_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(200) not null,\nTRIGGER_GROUP varchar(200) not null,\nJOB_NAME varchar(200) not null,\nJOB_GROUP varchar(200) not null,\nDESCRIPTION varchar(250) null,\nNEXT_FIRE_TIME numeric(13,0) null,\nPREV_FIRE_TIME numeric(13,0) null,\nPRIORITY int null,\nTRIGGER_STATE varchar(16) not null,\nTRIGGER_TYPE varchar(8) not null,\nSTART_TIME numeric(13,0) not null,\nEND_TIME numeric(13,0) null,\nCALENDAR_NAME varchar(200) null,\nMISFIRE_INSTR smallint null,\nJOB_DATA image null\n)\ngo\n\n/*==============================================================================*/\n/* Create primary key constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_CALENDARS\nadd constraint PK_qrtz_calendars primary key clustered (SCHED_NAME,CALENDAR_NAME)\ngo\n\nalter table QRTZ_CRON_TRIGGERS\nadd constraint PK_qrtz_cron_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_FIRED_TRIGGERS\nadd constraint PK_qrtz_fired_triggers primary key clustered (SCHED_NAME,ENTRY_ID)\ngo\n\nalter table QRTZ_PAUSED_TRIGGER_GRPS\nadd constraint PK_qrtz_paused_trigger_grps primary key clustered (SCHED_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SCHEDULER_STATE\nadd constraint PK_qrtz_scheduler_state primary key clustered (SCHED_NAME,INSTANCE_NAME)\ngo\n\nalter table QRTZ_LOCKS\nadd constraint PK_qrtz_locks primary key clustered (SCHED_NAME,LOCK_NAME)\ngo\n\nalter table QRTZ_JOB_DETAILS\nadd constraint PK_qrtz_job_details primary key clustered (SCHED_NAME,JOB_NAME, JOB_GROUP)\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\nadd constraint PK_qrtz_simple_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\nadd constraint PK_qrtz_simprop_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_TRIGGERS\nadd constraint PK_qrtz_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\nadd constraint PK_qrtz_blob_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\n\n/*==============================================================================*/\n/* Create foreign key constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_CRON_TRIGGERS\nadd constraint FK_cron_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\nadd constraint FK_simple_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\nadd constraint FK_simprop_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_TRIGGERS\nadd constraint FK_triggers_job_details foreign key (SCHED_NAME,JOB_NAME,JOB_GROUP)\nreferences QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP)\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\nadd constraint FK_blob_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\n/*==============================================================================*/\n/* End of script. */\n/*==============================================================================*/\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/quartz.properties",
    "content": "# Default Properties file for use by StdSchedulerFactory\n# to create a Quartz Scheduler Instance, if a different\n# properties file is not explicitly specified.\n#\n\norg.quartz.scheduler.instanceName: DefaultQuartzScheduler\norg.quartz.scheduler.rmi.export: false\norg.quartz.scheduler.rmi.proxy: false\norg.quartz.scheduler.wrapJobExecutionInUserTransaction: false\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 10\norg.quartz.threadPool.threadPriority: 5\norg.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/xml/job_scheduling_data_1_8.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n    xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    targetNamespace=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    elementFormDefault=\"qualified\"\n    version=\"1.8\"> \n    \n    <xs:element name=\"job-scheduling-data\">\n        <xs:annotation>\n            <xs:documentation>Root level node</xs:documentation>\n        </xs:annotation>\n        <xs:complexType>\n            <xs:sequence maxOccurs=\"unbounded\">\n                <xs:element name=\"pre-processing-commands\" type=\"pre-processing-commandsType\" minOccurs=\"0\" maxOccurs=\"1\">\n                    <xs:annotation>\n                        <xs:documentation>Commands to be executed before scheduling the jobs and triggers in this file.</xs:documentation>\n                    </xs:annotation>\n                </xs:element>\n                <xs:element name=\"processing-directives\" type=\"processing-directivesType\" minOccurs=\"0\" maxOccurs=\"1\">\n                    <xs:annotation>\n                        <xs:documentation>Directives to be followed while scheduling the jobs and triggers in this file.</xs:documentation>\n                    </xs:annotation>\n                </xs:element>\n                <xs:element name=\"schedule\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xs:complexType>\n                        <xs:sequence maxOccurs=\"unbounded\">\n                            <xs:element name=\"job\" type=\"job-detailType\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                            <xs:element name=\"trigger\" type=\"triggerType\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                        </xs:sequence>\n                    </xs:complexType>\n                </xs:element>\n            </xs:sequence>\n            <xs:attribute name=\"version\" type=\"xs:string\">\n                <xs:annotation>\n                    <xs:documentation>Version of the XML Schema instance</xs:documentation>\n                </xs:annotation>\n            </xs:attribute>\n        </xs:complexType>\n    </xs:element>\n    \n    <xs:complexType name=\"pre-processing-commandsType\">\n        <xs:sequence maxOccurs=\"unbounded\">\n            <xs:element name=\"delete-jobs-in-group\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"delete-triggers-in-group\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"delete-job\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>Delete the identified job if it exists (will also result in deleting all triggers related to it).</xs:documentation></xs:annotation>\n                <xs:complexType>\n                    <xs:sequence>\n                        <xs:element name=\"name\" type=\"xs:string\"/>\n                        <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n                    </xs:sequence>\n                </xs:complexType>\n            </xs:element>\n            <xs:element name=\"delete-trigger\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable).</xs:documentation></xs:annotation>\n                <xs:complexType>\n                    <xs:sequence>\n                        <xs:element name=\"name\" type=\"xs:string\"/>\n                        <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n                    </xs:sequence>\n                </xs:complexType>\n            </xs:element>\n        </xs:sequence>\n    </xs:complexType>\n\n    <xs:complexType name=\"processing-directivesType\">\n        <xs:sequence>\n            <xs:element name=\"overwrite-existing-data\" type=\"xs:boolean\" minOccurs=\"0\" default=\"true\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"ignore-duplicates\" type=\"xs:boolean\" minOccurs=\"0\" default=\"false\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"job-detailType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDetail</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"name\" type=\"xs:string\"/>\n            <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"description\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"job-class\" type=\"xs:string\"/>\n            <xs:element name=\"job-listener-ref\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:sequence minOccurs=\"0\">\n                <xs:element name=\"volatility\" type=\"xs:boolean\"/>\n                <xs:element name=\"durability\" type=\"xs:boolean\"/>\n                <xs:element name=\"recover\" type=\"xs:boolean\"/>\n            </xs:sequence>\n            <xs:element name=\"job-data-map\" type=\"job-data-mapType\" minOccurs=\"0\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"job-data-mapType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDataMap</xs:documentation>\n        </xs:annotation>\n        <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xs:element name=\"entry\" type=\"entryType\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"entryType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDataMap entry</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"key\" type=\"xs:string\"/>\n            <xs:element name=\"value\" type=\"xs:string\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"triggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a Trigger</xs:documentation>\n        </xs:annotation>\n        <xs:choice>\n            <xs:element name=\"simple\" type=\"simpleTriggerType\"/>\n            <xs:element name=\"cron\" type=\"cronTriggerType\"/>\n            <xs:element name=\"date-interval\" type=\"dateIntervalTriggerType\"/>\n        </xs:choice>\n    </xs:complexType>\n    \n    <xs:complexType name=\"abstractTriggerType\" abstract=\"true\">\n        <xs:annotation>\n            <xs:documentation>Common Trigger definitions</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"name\" type=\"xs:string\"/>\n            <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"description\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"job-name\" type=\"xs:string\"/>\n            <xs:element name=\"job-group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"calendar-name\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"volatility\" type=\"xs:boolean\"  minOccurs=\"0\"/>\n            <xs:element name=\"job-data-map\" type=\"job-data-mapType\" minOccurs=\"0\"/>\n            <xs:sequence minOccurs=\"0\">\n                <xs:element name=\"start-time\" type=\"xs:dateTime\"/>\n                <xs:element name=\"end-time\"  type=\"xs:dateTime\" minOccurs=\"0\"/>\n            </xs:sequence>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"simpleTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a SimpleTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"simple-trigger-misfire-instructionType\" minOccurs=\"0\" />\n                    <xs:sequence minOccurs=\"0\">\n                        <xs:element name=\"repeat-count\" type=\"repeat-countType\"/>\n                        <xs:element name=\"repeat-interval\" type=\"xs:nonNegativeInteger\"/>\n                    </xs:sequence>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:complexType name=\"cronTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a CronTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"cron-trigger-misfire-instructionType\"  minOccurs=\"0\"/>\n                    <xs:element name=\"cron-expression\" type=\"cron-expressionType\"/>\n                    <xs:element name=\"time-zone\" type=\"xs:string\" minOccurs=\"0\"/>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:complexType name=\"dateIntervalTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a DateIntervalTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"date-interval-trigger-misfire-instructionType\"  minOccurs=\"0\"/>\n                    <xs:element name=\"repeat-interval\" type=\"xs:nonNegativeInteger\"/>\n                    <xs:element name=\"repeat-interval-unit\" type=\"interval-unitType\"/>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:simpleType name=\"cron-expressionType\">\n        <xs:annotation>\n            <xs:documentation>\n                Cron expression (see JavaDoc for examples)\n                \n                Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression!\n                \n                Regular expressions are not my strong point but I believe this is complete,\n                with the caveat that order for expressions like 3-0 is not legal but will pass, \n                and month and day names must be capitalized.\n                If you want to examine the correctness look for the [\\s] to denote the\n                separation of individual regular expressions. This is how I break them up visually \n                to examine them:\n                \n                SECONDS:\n                (   \n                ((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9]))\n                | (([\\*]|[0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9]))\n                | ([\\?])\n                | ([\\*])\n                ) [\\s]\n                MINUTES:\n                (   \n                ((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9]))\n                | (([\\*]|[0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9]))\n                | ([\\?])\n                | ([\\*])\n                ) [\\s]\n                HOURS:\n                (\n                ((([0-9]|[0-1][0-9]|[2][0-3]),)*([0-9]|[0-1][0-9]|[2][0-3]))\n                | (([\\*]|[0-9]|[0-1][0-9]|[2][0-3])(/|-)([0-9]|[0-1][0-9]|[2][0-3])) \n                | ([\\?])\n                | ([\\*]) \n                ) [\\s]\n                DAY OF MONTH:\n                (\n                ((([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)?)\n                | (([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)?)\n                | (L)\n                | (LW)\n                | ([1-9]W)\n                | ([1-3][0-9]W)\n                | ([\\?])\n                | ([\\*])\n                )[\\s]\n                MONTH:\n                (  \n                ((([1-9]|0[1-9]|1[0-2]),)*([1-9]|0[1-9]|1[0-2]))\n                | (([1-9]|0[1-9]|1[0-2])(/|-)([1-9]|0[1-9]|1[0-2]))\n                | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC),)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))\n                | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-|/)(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))\n                | ([\\?])\n                | ([\\*])\n                )[\\s]\n                DAY OF WEEK:\n                ( \n                (([1-7],)*([1-7]))\n                | ([1-7](/|-)([1-7]))\n                | (((MON|TUE|WED|THU|FRI|SAT|SUN),)*(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)\n                | ((MON|TUE|WED|THU|FRI|SAT|SUN)(-|/)(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)\n                | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?)\n                | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)\n                | ([\\?])\n                | ([\\*])\n                )\n                YEAR (OPTIONAL):\n                (\n                [\\s]?\n                ([\\*])?\n                | ((19[7-9][0-9])|(20[0-9][0-9]))?\n                | (((19[7-9][0-9])|(20[0-9][0-9]))(-|/)((19[7-9][0-9])|(20[0-9][0-9])))?\n                | ((((19[7-9][0-9])|(20[0-9][0-9])),)*((19[7-9][0-9])|(20[0-9][0-9])))?\n                )\n            </xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"(((([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](((([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](((([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](((([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](((([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]((([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])?)|([\\?])|([\\*]))([\\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])))?)\"/> \n        </xs:restriction>\n    </xs:simpleType>\n     \n    <xs:simpleType name=\"repeat-countType\">\n        <xs:annotation>\n            <xs:documentation>Number of times to repeat the Trigger (-1 for indefinite)</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:integer\">\n            <xs:minInclusive value=\"-1\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n   \n    <xs:simpleType name=\"simple-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Simple Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"cron-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Simple Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_DO_NOTHING\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"date-interval-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Date Interval Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_DO_NOTHING\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"interval-unitType\">\n        <xs:annotation>\n            <xs:documentation>Interval Units</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"DAY\"/>\n            <xs:pattern value=\"HOUR\"/>\n            <xs:pattern value=\"MINUTE\"/>\n            <xs:pattern value=\"MONTH\"/>\n            <xs:pattern value=\"SECOND\"/>\n            <xs:pattern value=\"WEEK\"/>\n            <xs:pattern value=\"YEAR\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n</xs:schema>\n"
  },
  {
    "path": "quartz/src/main/resources/org/quartz/xml/job_scheduling_data_2_0.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n    xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    targetNamespace=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    elementFormDefault=\"qualified\"\n    version=\"2.0\"> \n    \n    <xs:element name=\"job-scheduling-data\">\n        <xs:annotation>\n            <xs:documentation>Root level node</xs:documentation>\n        </xs:annotation>\n        <xs:complexType>\n            <xs:sequence maxOccurs=\"unbounded\">\n                <xs:element name=\"pre-processing-commands\" type=\"pre-processing-commandsType\" minOccurs=\"0\" maxOccurs=\"1\">\n                    <xs:annotation>\n                        <xs:documentation>Commands to be executed before scheduling the jobs and triggers in this file.</xs:documentation>\n                    </xs:annotation>\n                </xs:element>\n                <xs:element name=\"processing-directives\" type=\"processing-directivesType\" minOccurs=\"0\" maxOccurs=\"1\">\n                    <xs:annotation>\n                        <xs:documentation>Directives to be followed while scheduling the jobs and triggers in this file.</xs:documentation>\n                    </xs:annotation>\n                </xs:element>\n                <xs:element name=\"schedule\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xs:complexType>\n                        <xs:sequence maxOccurs=\"unbounded\">\n                            <xs:element name=\"job\" type=\"job-detailType\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                            <xs:element name=\"trigger\" type=\"triggerType\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                        </xs:sequence>\n                    </xs:complexType>\n                </xs:element>\n            </xs:sequence>\n            <xs:attribute name=\"version\" type=\"xs:string\">\n                <xs:annotation>\n                    <xs:documentation>Version of the XML Schema instance</xs:documentation>\n                </xs:annotation>\n            </xs:attribute>\n        </xs:complexType>\n    </xs:element>\n    \n    <xs:complexType name=\"pre-processing-commandsType\">\n        <xs:sequence maxOccurs=\"unbounded\">\n            <xs:element name=\"delete-jobs-in-group\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"delete-triggers-in-group\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"delete-job\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>Delete the identified job if it exists (will also result in deleting all triggers related to it).</xs:documentation></xs:annotation>\n                <xs:complexType>\n                    <xs:sequence>\n                        <xs:element name=\"name\" type=\"xs:string\"/>\n                        <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n                    </xs:sequence>\n                </xs:complexType>\n            </xs:element>\n            <xs:element name=\"delete-trigger\" minOccurs=\"0\" maxOccurs=\"unbounded\">\n                <xs:annotation><xs:documentation>Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable).</xs:documentation></xs:annotation>\n                <xs:complexType>\n                    <xs:sequence>\n                        <xs:element name=\"name\" type=\"xs:string\"/>\n                        <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n                    </xs:sequence>\n                </xs:complexType>\n            </xs:element>\n        </xs:sequence>\n    </xs:complexType>\n\n    <xs:complexType name=\"processing-directivesType\">\n        <xs:sequence>\n            <xs:element name=\"overwrite-existing-data\" type=\"xs:boolean\" minOccurs=\"0\" default=\"true\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n            <xs:element name=\"ignore-duplicates\" type=\"xs:boolean\" minOccurs=\"0\" default=\"false\">\n                <xs:annotation><xs:documentation>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.</xs:documentation></xs:annotation>\n            </xs:element>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"job-detailType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDetail</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"name\" type=\"xs:string\"/>\n            <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"description\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"job-class\" type=\"xs:string\"/>\n            <xs:sequence minOccurs=\"0\">\n                <xs:element name=\"durability\" type=\"xs:boolean\"/>\n                <xs:element name=\"recover\" type=\"xs:boolean\"/>\n            </xs:sequence>\n            <xs:element name=\"job-data-map\" type=\"job-data-mapType\" minOccurs=\"0\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"job-data-mapType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDataMap</xs:documentation>\n        </xs:annotation>\n        <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xs:element name=\"entry\" type=\"entryType\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"entryType\">\n        <xs:annotation>\n            <xs:documentation>Define a JobDataMap entry</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"key\" type=\"xs:string\"/>\n            <xs:element name=\"value\" type=\"xs:string\"/>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"triggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a Trigger</xs:documentation>\n        </xs:annotation>\n        <xs:choice>\n            <xs:element name=\"simple\" type=\"simpleTriggerType\"/>\n            <xs:element name=\"cron\" type=\"cronTriggerType\"/>\n            <xs:element name=\"calendar-interval\" type=\"calendarIntervalTriggerType\"/>\n        </xs:choice>\n    </xs:complexType>\n    \n    <xs:complexType name=\"abstractTriggerType\" abstract=\"true\">\n        <xs:annotation>\n            <xs:documentation>Common Trigger definitions</xs:documentation>\n        </xs:annotation>\n        <xs:sequence>\n            <xs:element name=\"name\" type=\"xs:string\"/>\n            <xs:element name=\"group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"description\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"job-name\" type=\"xs:string\"/>\n            <xs:element name=\"job-group\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"priority\" type=\"xs:nonNegativeInteger\" minOccurs=\"0\"/>\n            <xs:element name=\"calendar-name\" type=\"xs:string\" minOccurs=\"0\"/>\n            <xs:element name=\"job-data-map\" type=\"job-data-mapType\" minOccurs=\"0\"/>\n            <xs:sequence minOccurs=\"0\">\n                <xs:choice>\n                    <xs:element name=\"start-time\" type=\"xs:dateTime\"/>\n                    <xs:element name=\"start-time-seconds-in-future\" type=\"xs:nonNegativeInteger\"/>\n                </xs:choice>\n                <xs:element name=\"end-time\"  type=\"xs:dateTime\" minOccurs=\"0\"/>\n            </xs:sequence>\n        </xs:sequence>\n    </xs:complexType>\n    \n    <xs:complexType name=\"simpleTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a SimpleTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"simple-trigger-misfire-instructionType\" minOccurs=\"0\" />\n                    <xs:sequence minOccurs=\"0\">\n                        <xs:element name=\"repeat-count\" type=\"repeat-countType\"/>\n                        <xs:element name=\"repeat-interval\" type=\"xs:nonNegativeInteger\"/>\n                    </xs:sequence>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:complexType name=\"cronTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a CronTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"cron-trigger-misfire-instructionType\"  minOccurs=\"0\"/>\n                    <xs:element name=\"cron-expression\" type=\"cron-expressionType\"/>\n                    <xs:element name=\"time-zone\" type=\"xs:string\" minOccurs=\"0\"/>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:complexType name=\"calendarIntervalTriggerType\">\n        <xs:annotation>\n            <xs:documentation>Define a DateIntervalTrigger</xs:documentation>\n        </xs:annotation>\n        <xs:complexContent>\n            <xs:extension base=\"abstractTriggerType\">\n                <xs:sequence>\n                    <xs:element name=\"misfire-instruction\" type=\"date-interval-trigger-misfire-instructionType\"  minOccurs=\"0\"/>\n                    <xs:element name=\"repeat-interval\" type=\"xs:nonNegativeInteger\"/>\n                    <xs:element name=\"repeat-interval-unit\" type=\"interval-unitType\"/>\n                </xs:sequence>\n            </xs:extension>\n        </xs:complexContent>\n    </xs:complexType>\n    \n    <xs:simpleType name=\"cron-expressionType\">\n        <xs:annotation>\n            <xs:documentation>\n                Cron expression (see JavaDoc for examples)\n                \n                Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression!\n                \n                Regular expressions are not my strong point but I believe this is complete,\n                with the caveat that order for expressions like 3-0 is not legal but will pass, \n                and month and day names must be capitalized.\n                If you want to examine the correctness look for the [\\s] to denote the\n                separation of individual regular expressions. This is how I break them up visually \n                to examine them:\n                \n                SECONDS:\n                (   \n                ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)\n                | (([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))\n                | ([\\?])\n                | ([\\*])\n                ) [\\s]\n                MINUTES:\n                (   \n                ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)\n                | (([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))\n                | ([\\?])\n                | ([\\*])\n                ) [\\s]\n                HOURS:\n                (\n                ((([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]))?)\n                | (([\\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))\n                | ([\\?])\n                | ([\\*]) \n                ) [\\s]\n                DAY OF MONTH:\n                (\n                ((([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)?)\n                | (([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)?)\n                | (L(-[0-9])?)\n                | (L(-[1-2][0-9])?)\n                | (L(-[3][0-1])?)\n                | (LW)\n                | ([1-9]W)\n                | ([1-3][0-9]W)\n                | ([\\?])\n                | ([\\*])\n                )[\\s]\n                MONTH:\n                (  \n                ((([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]))?)\n                | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))\n                | (((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))?)\n                | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))\n                | ([\\?])\n                | ([\\*])\n                )[\\s]\n                DAY OF WEEK:\n                ( \n                (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)\n                | ([1-7]/([1-7]))\n                | (((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)?)\n                | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)\n                | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?)\n                | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)\n                | ([\\?])\n                | ([\\*])\n                )\n                YEAR (OPTIONAL):\n                (\n                [\\s]?\n                ([\\*])?\n                | ((19[7-9][0-9])|(20[0-9][0-9]))?\n                | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?\n                | ((((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])))?)?\n                )\n            </xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"(((([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](((([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](((([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](((([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](((([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]((([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])?)|([\\?])|([\\*]))([\\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])))?)?)\"/>\n        </xs:restriction>\n    </xs:simpleType>\n     \n    <xs:simpleType name=\"repeat-countType\">\n        <xs:annotation>\n            <xs:documentation>Number of times to repeat the Trigger (-1 for indefinite)</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:integer\">\n            <xs:minInclusive value=\"-1\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n   \n    <xs:simpleType name=\"simple-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Simple Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"cron-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Cron Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_DO_NOTHING\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"date-interval-trigger-misfire-instructionType\">\n        <xs:annotation>\n            <xs:documentation>Date Interval Trigger Misfire Instructions</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_SMART_POLICY\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_DO_NOTHING\"/>\n            <xs:pattern value=\"MISFIRE_INSTRUCTION_FIRE_ONCE_NOW\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n    <xs:simpleType name=\"interval-unitType\">\n        <xs:annotation>\n            <xs:documentation>Interval Units</xs:documentation>\n        </xs:annotation>\n        <xs:restriction base=\"xs:string\">\n            <xs:pattern value=\"DAY\"/>\n            <xs:pattern value=\"HOUR\"/>\n            <xs:pattern value=\"MINUTE\"/>\n            <xs:pattern value=\"MONTH\"/>\n            <xs:pattern value=\"SECOND\"/>\n            <xs:pattern value=\"WEEK\"/>\n            <xs:pattern value=\"YEAR\"/>\n        </xs:restriction>\n    </xs:simpleType>\n    \n</xs:schema>\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/AbstractJobStoreTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.junit.jupiter.api.DynamicTest.dynamicTest;\nimport static org.quartz.DailyTimeIntervalScheduleBuilder.MONDAY_THROUGH_FRIDAY;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.impl.JobDetailImpl;\nimport org.quartz.impl.jdbcjobstore.JobStoreSupport;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.simpl.CascadingClassLoadHelper;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.JobStore;\nimport org.quartz.spi.OperableTrigger;\nimport org.quartz.spi.SchedulerSignaler;\nimport org.quartz.spi.TriggerFiredResult;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.DynamicTest;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestFactory;\nimport org.junit.jupiter.api.TestInfo;\n\n\n/**\n * Unit test for JobStores.  These tests were submitted by Johannes Zillmann\n * as part of issue QUARTZ-306.\n */\npublic abstract class AbstractJobStoreTest  {\n    private JobStore fJobStore;\n    private JobDetailImpl fJobDetail;\n    private SampleSignaler fSignaler;\n    private TestInfo testInfo;\n\n    @SuppressWarnings(\"deprecation\")\n    @BeforeEach\n    protected void setUp(TestInfo testInfo) throws Exception {\n        this.testInfo = testInfo;\n        this.fSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n        this.fJobStore = createJobStore(\"AbstractJobStoreTest\");\n        this.fJobStore.initialize(loadHelper, this.fSignaler);\n        this.fJobStore.schedulerStarted();\n\n        this.fJobDetail = new JobDetailImpl(\"job1\", \"jobGroup1\", MyJob.class);\n        this.fJobDetail.setDurability(true);\n        this.fJobStore.storeJob(this.fJobDetail, false);\n    }\n\n    @AfterEach\n    protected void tearDown() {\n        if (fJobStore instanceof JobStoreSupport) {\n            //default to false\n            ((JobStoreSupport) fJobStore).setUseEnhancedStatements(false);\n        }\n        destroyJobStore(\"AbstractJobStoreTest\");\n    }\n\n    /**\n     * Creates a jobstore using the method name\n     * @return the jobstore\n     */\n    protected JobStore createJobStore() {\n        return createJobStore(testInfo.getTestMethod().map(Method::getName)\n            .orElseGet(testInfo::getDisplayName).replace(\" \", \"_\"));\n    }\n\n    protected abstract JobStore createJobStore(String name);\n\n    protected abstract void destroyJobStore(String name);\n\n    protected abstract Map<String, ? extends JobStore> stores();\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testAcquireNextTrigger() throws Exception {\n    \t\n    \tDate baseFireTimeDate = DateBuilder.evenMinuteDateAfterNow();\n    \tlong baseFireTime = baseFireTimeDate.getTime();\n    \t\n        OperableTrigger trigger1 = \n            new SimpleTriggerImpl(\"trigger1\", \"triggerGroup1\", this.fJobDetail.getName(), \n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 200000), \n                    new Date(baseFireTime + 200000), 2, 2000);\n        OperableTrigger trigger2 = \n            new SimpleTriggerImpl(\"trigger2\", \"triggerGroup1\", this.fJobDetail.getName(), \n                    this.fJobDetail.getGroup(), new Date(baseFireTime +  50000),\n                    new Date(baseFireTime + 200000), 2, 2000);\n        OperableTrigger trigger3 = \n            new SimpleTriggerImpl(\"trigger1\", \"triggerGroup2\", this.fJobDetail.getName(), \n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 100000), \n                    new Date(baseFireTime + 200000), 2, 2000);\n\n        trigger1.computeFirstFireTime(null);\n        trigger2.computeFirstFireTime(null);\n        trigger3.computeFirstFireTime(null);\n        this.fJobStore.storeTrigger(trigger1, false);\n        this.fJobStore.storeTrigger(trigger2, false);\n        this.fJobStore.storeTrigger(trigger3, false);\n        \n        long firstFireTime = new Date(trigger1.getNextFireTime().getTime()).getTime();\n\n        assertTrue(this.fJobStore.acquireNextTriggers(10, 1, 0L).isEmpty());\n        assertEquals(\n            trigger2.getKey(), \n            this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 1, 0L).get(0).getKey());\n        assertEquals(\n            trigger3.getKey(), \n            this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 1, 0L).get(0).getKey());\n        assertEquals(\n            trigger1.getKey(), \n            this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 1, 0L).get(0).getKey());\n        assertTrue(\n            this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 1, 0L).isEmpty());\n\n\n        // release trigger3\n        this.fJobStore.releaseAcquiredTrigger(trigger3);\n        assertEquals(\n            trigger3, \n            this.fJobStore.acquireNextTriggers(new Date(trigger1.getNextFireTime().getTime()).getTime() + 10000, 1, 1L).get(0));\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testAcquireNextTriggerBatch() throws Exception {\n    \t\n    \tlong baseFireTime = System.currentTimeMillis() - 1000;\n    \t\n        OperableTrigger early =\n            new SimpleTriggerImpl(\"early\", \"triggerGroup1\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime),\n                    new Date(baseFireTime + 5), 2, 2000);\n        OperableTrigger trigger1 =\n            new SimpleTriggerImpl(\"trigger1\", \"triggerGroup1\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 200000),\n                    new Date(baseFireTime + 200005), 2, 2000);\n        OperableTrigger trigger2 =\n            new SimpleTriggerImpl(\"trigger2\", \"triggerGroup1\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 210000),\n                    new Date(baseFireTime + 210005), 2, 2000);\n        OperableTrigger trigger3 =\n            new SimpleTriggerImpl(\"trigger3\", \"triggerGroup1\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 220000),\n                    new Date(baseFireTime + 220005), 2, 2000);\n        OperableTrigger trigger4 =\n            new SimpleTriggerImpl(\"trigger4\", \"triggerGroup1\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 230000),\n                    new Date(baseFireTime + 230005), 2, 2000);\n\n        OperableTrigger trigger10 =\n            new SimpleTriggerImpl(\"trigger10\", \"triggerGroup2\", this.fJobDetail.getName(),\n                    this.fJobDetail.getGroup(), new Date(baseFireTime + 500000),\n                    new Date(baseFireTime + 700000), 2, 2000);\n\n        early.computeFirstFireTime(null);\n        early.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n        trigger1.computeFirstFireTime(null);\n        trigger2.computeFirstFireTime(null);\n        trigger3.computeFirstFireTime(null);\n        trigger4.computeFirstFireTime(null);\n        trigger10.computeFirstFireTime(null);\n        this.fJobStore.storeTrigger(early, false);\n        this.fJobStore.storeTrigger(trigger1, false);\n        this.fJobStore.storeTrigger(trigger2, false);\n        this.fJobStore.storeTrigger(trigger3, false);\n        this.fJobStore.storeTrigger(trigger4, false);\n        this.fJobStore.storeTrigger(trigger10, false);\n        \n        long firstFireTime = new Date(trigger1.getNextFireTime().getTime()).getTime();\n\n        List<OperableTrigger> acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 4, 1000L);\n        assertEquals(1, acquiredTriggers.size());\n        assertEquals(early.getKey(), acquiredTriggers.get(0).getKey());\n        this.fJobStore.releaseAcquiredTrigger(early);\n\n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 4, 205000);\n        assertEquals(2, acquiredTriggers.size());\n        assertEquals(early.getKey(), acquiredTriggers.get(0).getKey());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(1).getKey());\n        this.fJobStore.releaseAcquiredTrigger(early);\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n        \n        this.fJobStore.removeTrigger(early.getKey());\n        \n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 5, 100000L);\n        assertEquals(4, acquiredTriggers.size());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(0).getKey());\n        assertEquals(trigger2.getKey(), acquiredTriggers.get(1).getKey());\n        assertEquals(trigger3.getKey(), acquiredTriggers.get(2).getKey());\n        assertEquals(trigger4.getKey(), acquiredTriggers.get(3).getKey());\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n        this.fJobStore.releaseAcquiredTrigger(trigger2);\n        this.fJobStore.releaseAcquiredTrigger(trigger3);\n        this.fJobStore.releaseAcquiredTrigger(trigger4);\n\n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 10000, 6, 100000L);\n        assertEquals(4, acquiredTriggers.size());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(0).getKey());\n        assertEquals(trigger2.getKey(), acquiredTriggers.get(1).getKey());\n        assertEquals(trigger3.getKey(), acquiredTriggers.get(2).getKey());\n        assertEquals(trigger4.getKey(), acquiredTriggers.get(3).getKey());\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n        this.fJobStore.releaseAcquiredTrigger(trigger2);\n        this.fJobStore.releaseAcquiredTrigger(trigger3);\n        this.fJobStore.releaseAcquiredTrigger(trigger4);\n\n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 1, 5, 0L);\n        assertEquals(1, acquiredTriggers.size());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(0).getKey());\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n\n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 250, 5, 19999L);\n        assertEquals(2, acquiredTriggers.size());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(0).getKey());\n        assertEquals(trigger2.getKey(), acquiredTriggers.get(1).getKey());\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n        this.fJobStore.releaseAcquiredTrigger(trigger2);\n        this.fJobStore.releaseAcquiredTrigger(trigger3);\n        \n        acquiredTriggers = this.fJobStore.acquireNextTriggers(firstFireTime + 150, 5, 5000L);\n        assertEquals(1, acquiredTriggers.size());\n        assertEquals(trigger1.getKey(), acquiredTriggers.get(0).getKey());\n        this.fJobStore.releaseAcquiredTrigger(trigger1);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testTriggerStates() throws Exception {\n        OperableTrigger trigger = \n            new SimpleTriggerImpl(\"trigger1\", \"triggerGroup1\", this.fJobDetail.getName(), this.fJobDetail.getGroup(), \n                    new Date(System.currentTimeMillis() + 100000), new Date(System.currentTimeMillis() + 200000), 2, 2000);\n        trigger.computeFirstFireTime(null);\n        assertEquals(TriggerState.NONE, this.fJobStore.getTriggerState(trigger.getKey()));\n        this.fJobStore.storeTrigger(trigger, false);\n        assertEquals(TriggerState.NORMAL, this.fJobStore.getTriggerState(trigger.getKey()));\n    \n        this.fJobStore.pauseTrigger(trigger.getKey());\n        assertEquals(TriggerState.PAUSED, this.fJobStore.getTriggerState(trigger.getKey()));\n    \n        this.fJobStore.resumeTrigger(trigger.getKey());\n        assertEquals(TriggerState.NORMAL, this.fJobStore.getTriggerState(trigger.getKey()));\n    \n        trigger = this.fJobStore.acquireNextTriggers(\n                new Date(trigger.getNextFireTime().getTime()).getTime() + 10000, 1, 1L).get(0);\n        assertNotNull(trigger);\n        this.fJobStore.releaseAcquiredTrigger(trigger);\n        trigger=this.fJobStore.acquireNextTriggers(\n                new Date(trigger.getNextFireTime().getTime()).getTime() + 10000, 1, 1L).get(0);\n        assertNotNull(trigger);\n        assertTrue(this.fJobStore.acquireNextTriggers(\n                new Date(trigger.getNextFireTime().getTime()).getTime() + 10000, 1, 1L).isEmpty());\n    }\n\n    // See: http://jira.opensymphony.com/browse/QUARTZ-606\n    @SuppressWarnings(\"deprecation\")\n    @Disabled\n    @Test\n    void testStoreTriggerReplacesTrigger() throws Exception {\n\n        String jobName = \"StoreTriggerReplacesTrigger\";\n        String jobGroup = \"StoreTriggerReplacesTriggerGroup\";\n        JobDetailImpl detail = new JobDetailImpl(jobName, jobGroup, MyJob.class);\n        fJobStore.storeJob(detail, false);\n \n        String trName = \"StoreTriggerReplacesTrigger\";\n        String trGroup = \"StoreTriggerReplacesTriggerGroup\";\n        OperableTrigger tr = new SimpleTriggerImpl(trName ,trGroup, new Date());\n        tr.setJobKey(new JobKey(jobName, jobGroup));\n        tr.setCalendarName(null);\n \n        fJobStore.storeTrigger(tr, false);\n        assertEquals(tr,fJobStore.retrieveTrigger(tr.getKey()));\n \n        try {\n            fJobStore.storeTrigger(tr, false);\n            fail(\"an attempt to store duplicate trigger succeeded\");\n        } catch(ObjectAlreadyExistsException oaee) {\n            // expected\n        }\n\n        tr.setCalendarName(\"QQ\");\n        fJobStore.storeTrigger(tr, true); //fails here\n        assertEquals(tr, fJobStore.retrieveTrigger(tr.getKey()));\n        assertEquals( \"StoreJob doesn't replace triggers\", \"QQ\", fJobStore.retrieveTrigger(tr.getKey()).getCalendarName());\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testPauseJobGroupPausesNewJob() throws Exception {\n    \t// Pausing job groups in JDBCJobStore is broken, see QTZ-208\n    \tif (fJobStore instanceof JobStoreSupport)\n    \t\treturn;\n    \t\n    \tfinal String jobName1 = \"PauseJobGroupPausesNewJob\";\n    \tfinal String jobName2 = \"PauseJobGroupPausesNewJob2\";\n    \tfinal String jobGroup = \"PauseJobGroupPausesNewJobGroup\";\n    \n    \tJobDetailImpl detail = new JobDetailImpl(jobName1, jobGroup, MyJob.class);\n    \tdetail.setDurability(true);\n    \tfJobStore.storeJob(detail, false);\n    \tfJobStore.pauseJobs(GroupMatcher.jobGroupEquals(jobGroup));\n    \n    \tdetail = new JobDetailImpl(jobName2, jobGroup, MyJob.class);\n    \tdetail.setDurability(true);\n    \tfJobStore.storeJob(detail, false);\n    \n    \tString trName = \"PauseJobGroupPausesNewJobTrigger\";\n    \tString trGroup = \"PauseJobGroupPausesNewJobTriggerGroup\";\n    \tOperableTrigger tr = new SimpleTriggerImpl(trName, trGroup, new Date());\n        tr.setJobKey(new JobKey(jobName2, jobGroup));\n    \tfJobStore.storeTrigger(tr, false);\n    \tassertEquals(TriggerState.PAUSED, fJobStore.getTriggerState(tr.getKey()));\n    }\n    \n    @Test\n    void testStoreAndRetrieveJobs() throws Exception {\n        SchedulerSignaler schedSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n\n        JobStore store = createJobStore(\"testStoreAndRetrieveJobs\");\n        store.initialize(loadHelper, schedSignaler);\n\t\t\n\t\t// Store jobs.\n\t\tfor (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n\t\t\tJobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i, group).build();\n\t\t\tstore.storeJob(job, false);\n\t\t}\n\t\t// Retrieve jobs.\n\t\tfor (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n\t\t\tJobKey jobKey = JobKey.jobKey(\"job\" + i, group);\n\t\t\tJobDetail storedJob = store.retrieveJob(jobKey);\n\t\t\tassertEquals(jobKey, storedJob.getKey());\n\t\t}\n        // Retrieve by group\n        assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(\"a\")).size(), \"Wrong number of jobs in group 'a'\");\n        assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(\"b\")).size(), \"Wrong number of jobs in group 'b'\");\n    }\n\n    @Test\n    void testStoreAndRetrieveJobsGroups() throws Exception {\n        SchedulerSignaler schedSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n\n        JobStore store = createJobStore(\"testStoreAndRetrieveJobsGroups\");\n        store.initialize(loadHelper, schedSignaler);\n\n        List<JobDetail> expectedJobs = new ArrayList<>(10);\n        // these will NOT be in order because of hashmap\n        // Store jobs.\n        for (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n            JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i, group).build();\n            store.storeJob(job, false);\n            expectedJobs.add(job);\n        }\n        List<JobKey> expectedKey = expectedJobs.stream().map(JobDetail::getKey).collect(Collectors.toList());\n        List<JobDetail> actual = store.getJobDetails(GroupMatcher.anyGroup());\n        Set<JobKey> jobKeys = actual.stream().map(JobDetail::getKey).collect(Collectors.toSet());\n        // Retrieve jobs.\n        for (int i=0; i < 10; i++) {\n            assertTrue(jobKeys.contains(actual.get(i).getKey()));\n            //assertEquals(expectedJobs.get(i).getKey(), actual.get(i).getKey(), \"Job does not matche expected\");\n        }\n\n        List<JobDetail> listA = store.getJobDetails(GroupMatcher.jobGroupEquals(\"a\"));\n        jobKeys = listA.stream().map(JobDetail::getKey).collect(Collectors.toSet());\n        assertEquals(5, listA.size(), \"Wrong number of jobs in group 'a'\");\n        for (int i=0; i < 5; i++) {\n            assertTrue(jobKeys.contains(expectedKey.get(i)));\n        }\n        List<JobDetail> listB = store.getJobDetails(GroupMatcher.jobGroupEquals(\"b\"));\n        jobKeys = listB.stream().map(JobDetail::getKey).collect(Collectors.toSet());\n\n        // Retrieve by group\n        assertEquals(5, listB.size(), \"Wrong number of jobs in group 'b'\");\n        for (int i=5; i < 10; i++) {\n            assertTrue(jobKeys.contains(expectedKey.get(i)));\n        }\n    }\n\n    private JobStore createVariedTriggers() throws JobPersistenceException, SchedulerConfigException{\n        SchedulerSignaler schedSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n\n        JobStore store = createJobStore();\n        store.initialize(loadHelper, schedSignaler);\n\n        // Store jobs and triggers.\n        for (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n            JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i, group).build();\n            store.storeJob(job, true);\n            Trigger trigger;\n            if (i == 0 || i == 5) {\n                trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"job\" + i, group)\n                    .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInDays(1))\n                    .forJob(job)\n                    .build();\n            } else if (i == 1 || i == 6) {\n                trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"job\" + i, group)\n                    .withSchedule(CronScheduleBuilder.cronSchedule(\"0 0 12 * * ?\"))\n                    .forJob(job)\n                    .build();\n            } else if (i == 2 || i == 7) {\n                trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"job\" + i, group)\n                    .withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n                        .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n                        .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0))\n                        .onDaysOfTheWeek(MONDAY_THROUGH_FRIDAY)\n                        .withIntervalInHours(1))\n                    .forJob(job)\n                    .build();\n            } else if (i == 3 || i  == 8){\n                trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"job\" + i, group)\n                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(15).repeatForever())\n                    .forJob(job)\n                    .build();\n            } else {\n                continue;\n            }\n            store.storeTrigger((OperableTrigger)trigger, true);\n        }\n        return store;\n    }\n\n    @Test\n    void testStoreAndRetrieveTriggers() throws Exception {\n        SchedulerSignaler schedSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n\n        JobStore store = createJobStore();\n        store.initialize(loadHelper, schedSignaler);\n\n        // Store jobs and triggers.\n        for (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n            JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i, group).build();\n            store.storeJob(job, true);\n            SimpleScheduleBuilder schedule = SimpleScheduleBuilder.simpleSchedule();\n            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"job\" + i, group).withSchedule(schedule).forJob(job).build();\n            store.storeTrigger((OperableTrigger)trigger, true);\n        }\n        // Retrieve job and trigger.\n        for (int i=0; i < 10; i++) {\n            String group =  i < 5 ? \"a\" : \"b\";\n            JobKey jobKey = JobKey.jobKey(\"job\" + i, group);\n            JobDetail storedJob = store.retrieveJob(jobKey);\n            assertEquals(jobKey, storedJob.getKey());\n\n            TriggerKey triggerKey = TriggerKey.triggerKey(\"job\" + i, group);\n            Trigger storedTrigger = store.retrieveTrigger(triggerKey);\n            assertEquals(triggerKey, storedTrigger.getKey());\n        }\n        // Retrieve by group\n        assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(\"a\")).size(), \"Wrong number of jobs in group 'a'\");\n        assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(\"b\")).size(), \"Wrong number of jobs in group 'b'\");\n    }\n\n    @TestFactory\n    Stream<DynamicTest> testEnhancedTriggerAndJobMatchers() throws Exception {\n        final JobStore store = createVariedTriggers();\n        final String A_GROUP = \"a\";\n        final String B_GROUP = \"b\";\n        return Stream.of(\n            dynamicTest(\"Get Group Jobs Enhanced\", () -> {\n                assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(A_GROUP)).size(),\n                    \"Wrong number of jobs in group: \" + A_GROUP);\n                assertEquals(5, store.getJobKeys(GroupMatcher.jobGroupEquals(B_GROUP)).size(),\n                    \"Wrong number of jobs in group: \" + B_GROUP);\n            }),\n            dynamicTest(\"Enhanced Trigger and JobMatcher test\", () -> {\n                for (int i=0; i < 10; i++) {\n                    String group =  i < 5 ? A_GROUP : B_GROUP;\n                    JobKey jobKey = JobKey.jobKey(\"job\" + i, group);\n                    JobDetail storedJob = store.retrieveJob(jobKey);\n                    assertEquals(jobKey, storedJob.getKey());\n\n                    TriggerKey triggerKey = TriggerKey.triggerKey(\"job\" + i, group);\n                    Trigger storedTrigger = store.retrieveTrigger(triggerKey);\n                    if (i != 4 && i != 9) {\n                        assertEquals(triggerKey, storedTrigger.getKey());\n                    } else {\n                        assertNull(storedTrigger);\n                    }\n                }\n            }),\n            dynamicTest(\"testStoreAndRetrieveTriggersJustTriggerGroupMatchers\", () -> {\n                //TODO: get by matcher\n                List<OperableTrigger> aTriggers = store.getTriggersByTriggerGroup(GroupMatcher.triggerGroupEquals(A_GROUP));\n                List<OperableTrigger> bTriggers = store.getTriggersByTriggerGroup(GroupMatcher.triggerGroupEquals(B_GROUP));\n                assertEquals(4, aTriggers.size(), \"Wrong number of jobs in group: \" + A_GROUP);\n                assertEquals(4, bTriggers.size(), \"Wrong number of jobs in group: \" + B_GROUP);\n            }),\n            dynamicTest(\"Match exact - only Job Group\", () -> {\n                //TODO: get by matcher\n                List<OperableTrigger> aTriggers = store.getTriggersByJobGroup(GroupMatcher.jobGroupEquals(A_GROUP));\n                List<OperableTrigger> bTriggers = store.getTriggersByJobGroup(GroupMatcher.jobGroupEquals(B_GROUP));\n                assertEquals(4, aTriggers.size(), \"Wrong number of jobs in group: \" + A_GROUP);\n                assertEquals(4, bTriggers.size(), \"Wrong number of jobs in group: \" + B_GROUP);\n            }),\n            dynamicTest(\"Match exact both\", () -> {\n                List<OperableTrigger> aTriggers = store.getTriggersByJobAndTriggerGroup(GroupMatcher.jobGroupEquals(A_GROUP), GroupMatcher.triggerGroupEquals(A_GROUP));\n                List<OperableTrigger> bTriggers = store.getTriggersByJobAndTriggerGroup(GroupMatcher.jobGroupEquals(B_GROUP), GroupMatcher.triggerGroupEquals(B_GROUP));\n                assertEquals(4, aTriggers.size(), \"Wrong number of jobs in group: \" + A_GROUP);\n                assertEquals(4, bTriggers.size(), \"Wrong number of jobs in group: \" + B_GROUP);\n            })\n        );\n    }\n\n    @Test\n    void testMatchers() throws Exception {\n        SchedulerSignaler schedSignaler = new SampleSignaler();\n        ClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n        loadHelper.initialize();\n\n        JobStore store = createJobStore(\"testMatchers\");\n        store.initialize(loadHelper, schedSignaler);\n\n        JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job1\", \"aaabbbccc\").build();\n        store.storeJob(job, true);\n        SimpleScheduleBuilder schedule = SimpleScheduleBuilder.simpleSchedule();\n        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"trig1\", \"aaabbbccc\").withSchedule(schedule).forJob(job).build();\n        store.storeTrigger((OperableTrigger) trigger, true);\n\n        job = JobBuilder.newJob(MyJob.class).withIdentity(\"job1\", \"xxxyyyzzz\").build();\n        store.storeJob(job, true);\n        schedule = SimpleScheduleBuilder.simpleSchedule();\n        trigger = TriggerBuilder.newTrigger().withIdentity(\"trig1\", \"xxxyyyzzz\").withSchedule(schedule).forJob(job).build();\n        store.storeTrigger((OperableTrigger) trigger, true);\n\n        job = JobBuilder.newJob(MyJob.class).withIdentity(\"job2\", \"xxxyyyzzz\").build();\n        store.storeJob(job, true);\n        schedule = SimpleScheduleBuilder.simpleSchedule();\n        trigger = TriggerBuilder.newTrigger().withIdentity(\"trig2\", \"xxxyyyzzz\").withSchedule(schedule).forJob(job).build();\n        store.storeTrigger((OperableTrigger) trigger, true);\n\n        Set<JobKey> jkeys = store.getJobKeys(GroupMatcher.anyJobGroup());\n        assertEquals(3, jkeys.size(), \"Wrong number of jobs found by anything matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupEquals(\"xxxyyyzzz\"));\n        assertEquals(2, jkeys.size(), \"Wrong number of jobs found by equals matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupEquals(\"aaabbbccc\"));\n        assertEquals(1, jkeys.size(), \"Wrong number of jobs found by equals matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupStartsWith(\"aa\"));\n        assertEquals(1, jkeys.size(), \"Wrong number of jobs found by starts with matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupStartsWith(\"xx\"));\n        assertEquals(2, jkeys.size(), \"Wrong number of jobs found by starts with matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupEndsWith(\"cc\"));\n        assertEquals(1, jkeys.size(), \"Wrong number of jobs found by ends with matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupEndsWith(\"zzz\"));\n        assertEquals(2, jkeys.size(), \"Wrong number of jobs found by ends with matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupContains(\"bc\"));\n        assertEquals(1, jkeys.size(), \"Wrong number of jobs found by contains with matcher\");\n\n        jkeys = store.getJobKeys(GroupMatcher.jobGroupContains(\"yz\"));\n        assertEquals(2, jkeys.size(), \"Wrong number of jobs found by contains with matcher\");\n\n        Set<TriggerKey> tkeys = store.getTriggerKeys(GroupMatcher.anyTriggerGroup());\n        assertEquals(3, tkeys.size(), \"Wrong number of triggers found by anything matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"xxxyyyzzz\"));\n        assertEquals(2, tkeys.size(), \"Wrong number of triggers found by equals matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"aaabbbccc\"));\n        assertEquals(1, tkeys.size(), \"Wrong number of triggers found by equals matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupStartsWith(\"aa\"));\n        assertEquals(1, tkeys.size(), \"Wrong number of triggers found by starts with matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupStartsWith(\"xx\"));\n        assertEquals(2, tkeys.size(), \"Wrong number of triggers found by starts with matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupEndsWith(\"cc\"));\n        assertEquals(1, tkeys.size(), \"Wrong number of triggers found by ends with matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupEndsWith(\"zzz\"));\n        assertEquals(2, tkeys.size(), \"Wrong number of triggers found by ends with matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupContains(\"bc\"));\n        assertEquals(1, tkeys.size(), \"Wrong number of triggers found by contains with matcher\");\n\n        tkeys = store.getTriggerKeys(GroupMatcher.triggerGroupContains(\"yz\"));\n        assertEquals(2, tkeys.size(), \"Wrong number of triggers found by contains with matcher\");\n    }\n\n    @Test\n\tvoid testAcquireTriggers() throws Exception {\n\t\tSchedulerSignaler schedSignaler = new SampleSignaler();\n\t\tClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n\t\tloadHelper.initialize();\n\t\t\n        JobStore store = createJobStore(\"testAcquireTriggers\");\n\t\tstore.initialize(loadHelper, schedSignaler);\n\t\t\n\t\t// Setup: Store jobs and triggers.\n\t\tlong MIN = 60 * 1000L;\n\t\tDate startTime0 = new Date(System.currentTimeMillis() + MIN); // a min from now.\n\t\tfor (int i=0; i < 10; i++) {\n\t\t\tDate startTime = new Date(startTime0.getTime() + i * MIN); // a min apart\n\t\t\tJobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i).build();\n\t\t\tSimpleScheduleBuilder schedule = SimpleScheduleBuilder.repeatMinutelyForever(2);\n\t\t\tOperableTrigger trigger = (OperableTrigger)TriggerBuilder.newTrigger().withIdentity(\"job\" + i).withSchedule(schedule).forJob(job).startAt(startTime).build();\n\t\t\t\n\t\t\t// Manually trigger the first fire time computation that scheduler would do. Otherwise \n\t\t\t// the store.acquireNextTriggers() will not work properly.\n\t        Date fireTime = trigger.computeFirstFireTime(null);\n            assertNotNull(fireTime);\n\t\t\t\n\t\t\tstore.storeJobAndTrigger(job, trigger);\n\t\t}\n\t\t\n\t\t// Test acquire one trigger at a time\n\t\tfor (int i=0; i < 10; i++) {\n\t\t\tlong noLaterThan = (startTime0.getTime() + i * MIN);\n\t\t\tint maxCount = 1;\n\t\t\tlong timeWindow = 0;\n\t\t\tList<OperableTrigger> triggers = store.acquireNextTriggers(noLaterThan, maxCount, timeWindow);\n\t\t\tassertEquals(1, triggers.size());\n\t\t\tassertEquals(\"job\" + i, triggers.get(0).getKey().getName());\n\t\t\t\n\t\t\t// Let's remove the trigger now.\n\t\t\tstore.removeJob(triggers.get(0).getJobKey());\n\t\t}\n\t}\n\t@Test\n\tvoid testAcquireTriggersInBatch() throws Exception {\n\t\tSchedulerSignaler schedSignaler = new SampleSignaler();\n\t\tClassLoadHelper loadHelper = new CascadingClassLoadHelper();\n\t\tloadHelper.initialize();\n\t\t\n        JobStore store = createJobStore(\"testAcquireTriggersInBatch\");\n\t\tstore.initialize(loadHelper, schedSignaler);\n\t\t\n\t\t// Setup: Store jobs and triggers.\n\t\tlong MIN = 60 * 1000L;\n\t\tDate startTime0 = new Date(System.currentTimeMillis() + MIN); // a min from now.\n\t\tfor (int i=0; i < 10; i++) {\n\t\t\tDate startTime = new Date(startTime0.getTime() + i * MIN); // a min apart\n\t\t\tJobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(\"job\" + i).build();\n\t\t\tSimpleScheduleBuilder schedule = SimpleScheduleBuilder.repeatMinutelyForever(2);\n\t\t\tOperableTrigger trigger = (OperableTrigger)TriggerBuilder.newTrigger().withIdentity(\"job\" + i).withSchedule(schedule).forJob(job).startAt(startTime).build();\n\t\t\t\n\t\t\t// Manually trigger the first fire time computation that scheduler would do. Otherwise \n\t\t\t// the store.acquireNextTriggers() will not work properly.\n\t        Date fireTime = trigger.computeFirstFireTime(null);\n            assertNotNull(fireTime);\n\t\t\t\n\t\t\tstore.storeJobAndTrigger(job, trigger);\n\t\t}\n\t\t\n\t\t// Test acquire batch of triggers at a time\n\t\tlong noLaterThan = startTime0.getTime() + 10 * MIN;\n\t\tint maxCount = 7;\n\t\t// time window needs to be big to be able to pick up multiple triggers when they are a minute apart\n\t\tlong timeWindow = 8 * MIN; \n\t\tList<OperableTrigger> triggers = store.acquireNextTriggers(noLaterThan, maxCount, timeWindow);\n\t\tassertEquals(7, triggers.size());\n\t\tfor (int i=0; i < 7; i++) {\n\t\t\tassertEquals(\"job\" + i, triggers.get(i).getKey().getName());\n\t\t}\n\t}\n\n    @Test\n    void testResetErrorTrigger() throws Exception {\n\n        Date baseFireTimeDate = DateBuilder.evenMinuteDateAfterNow();\n        long baseFireTime = baseFireTimeDate.getTime();\n\n        // create and store a trigger\n        OperableTrigger trigger1 =\n                new SimpleTriggerImpl(\"trigger1\", \"triggerGroup1\", this.fJobDetail.getName(),\n                        this.fJobDetail.getGroup(), new Date(baseFireTime + 200000),\n                        new Date(baseFireTime + 200000), 2, 2000);\n\n        trigger1.computeFirstFireTime(null);\n        this.fJobStore.storeTrigger(trigger1, false);\n\n        long firstFireTime = new Date(trigger1.getNextFireTime().getTime()).getTime();\n\n\n        // pretend to fire it\n        List<OperableTrigger> aqTs = this.fJobStore.acquireNextTriggers(\n                firstFireTime + 10000, 1, 0L);\n        assertEquals(trigger1.getKey(), aqTs.get(0).getKey());\n\n        List<TriggerFiredResult> fTs = this.fJobStore.triggersFired(aqTs);\n        TriggerFiredResult ft = fTs.get(0);\n\n        // get the trigger into error state\n        this.fJobStore.triggeredJobComplete(ft.getTriggerFiredBundle().getTrigger(), ft.getTriggerFiredBundle().getJobDetail(), Trigger.CompletedExecutionInstruction.SET_TRIGGER_ERROR);\n        TriggerState state = this.fJobStore.getTriggerState(trigger1.getKey());\n        assertEquals(TriggerState.ERROR, state);\n\n        // test reset\n        this.fJobStore.resetTriggerFromErrorState(trigger1.getKey());\n        state = this.fJobStore.getTriggerState(trigger1.getKey());\n        assertEquals(TriggerState.NORMAL, state);\n    }\n\n\n    @Test\n    void testStoreJobReplacesJob() throws Exception {\n\n        JobDetailImpl testJob = new JobDetailImpl(\"testDupeJob\", \"testDupeGroup\", MyJob.class);\n        testJob.setDescription(\"123abc\");\n        testJob.setDurability(true);\n\n        assertDoesNotThrow(() -> {\n            fJobStore.storeJob(testJob, false);\n        });\n\n        JobDetail origJob = fJobStore.retrieveJob(testJob.getKey());\n        assertNotNull(origJob);\n        assertEquals(testJob.getKey(), origJob.getKey());\n        assertEquals(testJob.getDescription(), origJob.getDescription());\n\n        JobDetailImpl dupeJob = new JobDetailImpl(\"testDupeJob\", \"testDupeGroup\", MyJob.class);\n        dupeJob.setDescription(\"123abc\");\n        dupeJob.setDurability(true);\n\n        assertThrows(SchedulerException.class, () -> {\n            fJobStore.storeJob(dupeJob, false);\n        }, \"storing a duplicate job should not succeed with replaceExisting=false\");\n\n        assertDoesNotThrow(() -> {\n            fJobStore.storeJob(dupeJob, true);\n        }, \"storing a duplicate job should succeed with replaceExisting=true\");\n\n        JobDetail reloadedJob = fJobStore.retrieveJob(testJob.getKey());\n        assertNotNull(reloadedJob);\n        assertEquals(testJob.getKey(), reloadedJob.getKey());\n        assertEquals(testJob.getDescription(), reloadedJob.getDescription());\n    }\n\n    public static class SampleSignaler implements SchedulerSignaler {\n        volatile int fMisfireCount = 0;\n\n        public void notifyTriggerListenersMisfired(Trigger trigger) {\n        \tSystem.out.println(\"Trigger misfired: \" + trigger.getKey() + \", fire time: \" + trigger.getNextFireTime());\n            fMisfireCount++;\n        }\n\n        public void signalSchedulingChange(long candidateNewNextFireTime) {\n        }\n\n        public void notifySchedulerListenersFinalized(Trigger trigger) {\n        }\n\n        public void notifySchedulerListenersJobDeleted(JobKey jobKey) {\n        }\n        \n        public void notifySchedulerListenersError(String string, SchedulerException jpe) {\n        }\n    }\n\n    /** An empty job for testing purpose. */\n    public static class MyJob implements Job {\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            //\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/AbstractSchedulerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.JobKey.jobKey;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\nimport static org.quartz.TriggerKey.triggerKey;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.impl.matchers.GroupMatcher;\n\n\n\n/**\n * Test High Level Scheduler functionality (implicitly tests the underlying jobstore (RAMJobStore))\n */\npublic abstract class AbstractSchedulerTest {\n\n    private static final String BARRIER = \"BARRIER\";\n    private static final String DATE_STAMPS = \"DATE_STAMPS\";\n    private static final String JOB_THREAD = \"JOB_THREAD\";\n\n    @SuppressWarnings(\"deprecation\")\n    public static class TestStatefulJob implements StatefulJob {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n\n    public static class TestJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n    \n\tpublic static final long TEST_TIMEOUT_SECONDS = 50;\n    \n    public static class TestJobWithSync implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        \t\n\t\t\ttry {\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tList<Long> jobExecTimestamps = (List<Long>)context.getScheduler().getContext().get(DATE_STAMPS);\n\t\t\t\tCyclicBarrier barrier =  (CyclicBarrier)context.getScheduler().getContext().get(BARRIER);\n\n\t        \tjobExecTimestamps.add(System.currentTimeMillis());\n\t        \t\n\t\t\t\tbarrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n\t\t\t} catch (Throwable e) {\n\t\t\t\te.printStackTrace();\n\t\t\t\tthrow new AssertionError(\"Await on barrier was interrupted: \" + e.toString());\n\t\t\t} \n        }\n    }\n    \n    @DisallowConcurrentExecution\n    @PersistJobDataAfterExecution\n    public static class TestAnnotatedJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n    \n    protected abstract Scheduler createScheduler(String name, int threadPoolSize) throws SchedulerException;\n\n    @Test\n    void testBasicStorageFunctions() throws Exception {\n        Scheduler sched = createScheduler(\"testBasicStorageFunctions\", 2);\n\n        // test basic storage functions of scheduler...\n        \n        JobDetail job = newJob()\n            .ofType(TestJob.class)\n            .withIdentity(\"j1\")\n            .storeDurably()\n            .build();\n\n        assertFalse(sched.checkExists(jobKey(\"j1\")), \"Unexpected existence of job named 'j1'.\");\n\n        sched.addJob(job, false); \n\n        assertTrue(sched.checkExists(jobKey(\"j1\")), \"Expected existence of job named 'j1' but checkExists return false.\");\n\n        job = sched.getJobDetail(jobKey(\"j1\"));\n\n        assertNotNull(job,\"Stored job not found!\");\n        \n        sched.deleteJob(jobKey(\"j1\"));\n        \n        Trigger trigger = newTrigger()\n            .withIdentity(\"t1\")\n            .forJob(job)\n            .startNow()\n            .withSchedule(simpleSchedule()\n                    .repeatForever()\n                    .withIntervalInSeconds(5))\n             .build();\n\n        assertFalse(sched.checkExists(triggerKey(\"t1\")), \"Unexpected existence of trigger named '11'.\");\n\n        sched.scheduleJob(job, trigger);\n        \n        assertTrue(sched.checkExists(triggerKey(\"t1\")), \"Expected existence of trigger named 't1' but checkExists return false.\");\n\n        job = sched.getJobDetail(jobKey(\"j1\"));\n\n        assertNotNull(job,\"Stored job not found!\");\n        \n        trigger = sched.getTrigger(triggerKey(\"t1\"));\n\n        assertNotNull(trigger,\"Stored trigger not found!\");\n\n        job = newJob()\n            .ofType(TestJob.class)\n            .withIdentity(\"j2\", \"g1\")\n            .build();\n    \n        trigger = newTrigger()\n            .withIdentity(\"t2\", \"g1\")\n            .forJob(job)\n            .startNow()\n            .withSchedule(simpleSchedule()\n                    .repeatForever()\n                    .withIntervalInSeconds(5))\n             .build();\n\n        sched.scheduleJob(job, trigger);\n        \n        job = newJob()\n            .ofType(TestJob.class)\n            .withIdentity(\"j3\", \"g1\")\n            .build();\n    \n        trigger = newTrigger()\n            .withIdentity(\"t3\", \"g1\")\n            .forJob(job)\n            .startNow()\n            .withSchedule(simpleSchedule()\n                    .repeatForever()\n                    .withIntervalInSeconds(5))\n             .build();\n    \n        sched.scheduleJob(job, trigger);\n        \n                \n        List<String> jobGroups = sched.getJobGroupNames();\n        List<String> triggerGroups = sched.getTriggerGroupNames();\n\n        assertEquals(2, jobGroups.size(), \"Job group list size expected to be = 2 \");\n        assertEquals(2, triggerGroups.size(), \"Trigger group list size expected to be = 2 \");\n        \n        Set<JobKey> jobKeys = sched.getJobKeys(GroupMatcher.jobGroupEquals(JobKey.DEFAULT_GROUP));\n        Set<TriggerKey> triggerKeys = sched.getTriggerKeys(GroupMatcher.triggerGroupEquals(TriggerKey.DEFAULT_GROUP));\n\n        assertEquals(1, jobKeys.size(), \"Number of jobs expected in default group was 1 \");\n        assertEquals(1, triggerKeys.size(), \"Number of triggers expected in default group was 1 \");\n\n        jobKeys = sched.getJobKeys(GroupMatcher.jobGroupEquals(\"g1\"));\n        triggerKeys = sched.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"g1\"));\n\n        assertEquals(2, jobKeys.size(), \"Number of jobs expected in 'g1' group was 2 \");\n        assertEquals(2, triggerKeys.size(), \"Number of triggers expected in 'g1' group was 2 \");\n\n        \n        TriggerState s = sched.getTriggerState(triggerKey(\"t2\", \"g1\"));\n        assertEquals(TriggerState.NORMAL, s, \"State of trigger t2 expected to be NORMAL \");\n        \n        sched.pauseTrigger(triggerKey(\"t2\", \"g1\"));\n        s = sched.getTriggerState(triggerKey(\"t2\", \"g1\"));\n        assertEquals(TriggerState.PAUSED, s, \"State of trigger t2 expected to be PAUSED \");\n\n        sched.resumeTrigger(triggerKey(\"t2\", \"g1\"));\n        s = sched.getTriggerState(triggerKey(\"t2\", \"g1\"));\n        assertEquals(TriggerState.NORMAL, s, \"State of trigger t2 expected to be NORMAL \");\n\n        Set<String> pausedGroups = sched.getPausedTriggerGroups();\n        assertTrue(pausedGroups.isEmpty(), \"Size of paused trigger groups list expected to be 0 \");\n        \n        sched.pauseTriggers(GroupMatcher.triggerGroupEquals(\"g1\"));\n        \n        // test that adding a trigger to a paused group causes the new trigger to be paused also... \n        job = newJob()\n            .ofType(TestJob.class)\n            .withIdentity(\"j4\", \"g1\")\n            .build();\n    \n        trigger = newTrigger()\n            .withIdentity(\"t4\", \"g1\")\n            .forJob(job)\n            .startNow()\n            .withSchedule(simpleSchedule()\n                    .repeatForever()\n                    .withIntervalInSeconds(5))\n             .build();\n    \n        sched.scheduleJob(job, trigger);\n\n        pausedGroups = sched.getPausedTriggerGroups();\n        assertEquals(1, pausedGroups.size(), \"Size of paused trigger groups list expected to be 1 \");\n\n        s = sched.getTriggerState(triggerKey(\"t2\", \"g1\"));\n        assertEquals(TriggerState.PAUSED, s, \"State of trigger t2 expected to be PAUSED \");\n\n        s = sched.getTriggerState(triggerKey(\"t4\", \"g1\"));\n        assertEquals(TriggerState.PAUSED, s, \"State of trigger t4 expected to be PAUSED \");\n        \n        sched.resumeTriggers(GroupMatcher.triggerGroupEquals(\"g1\"));\n        s = sched.getTriggerState(triggerKey(\"t2\", \"g1\"));\n        assertEquals(TriggerState.NORMAL, s, \"State of trigger t2 expected to be NORMAL \");\n        s = sched.getTriggerState(triggerKey(\"t4\", \"g1\"));\n        assertEquals(TriggerState.NORMAL, s, \"State of trigger t4 expected to be NORMAL \");\n        pausedGroups = sched.getPausedTriggerGroups();\n        assertEquals(0, pausedGroups.size(), \"Size of paused trigger groups list expected to be 0 \");\n\n        \n        assertFalse(sched.unscheduleJob(triggerKey(\"foasldfksajdflk\")), \"Scheduler should have returned 'false' from attempt to unschedule non-existing trigger. \");\n\n        assertTrue(sched.unscheduleJob(triggerKey(\"t3\", \"g1\")), \"Scheduler should have returned 'true' from attempt to unschedule existing trigger. \");\n        \n        jobKeys = sched.getJobKeys(GroupMatcher.jobGroupEquals(\"g1\"));\n        triggerKeys = sched.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"g1\"));\n\n        assertEquals(2, jobKeys.size(), \"Number of jobs expected in 'g1' group was 1 \"); // job should have been deleted also, because it is non-durable\n        assertEquals(2, triggerKeys.size(), \"Number of triggers expected in 'g1' group was 1 \");\n\n        assertTrue(sched.unscheduleJob(triggerKey(\"t1\")), \"Scheduler should have returned 'true' from attempt to unschedule existing trigger. \");\n        \n        jobKeys = sched.getJobKeys(GroupMatcher.jobGroupEquals(JobKey.DEFAULT_GROUP));\n        triggerKeys = sched.getTriggerKeys(GroupMatcher.triggerGroupEquals(TriggerKey.DEFAULT_GROUP));\n\n        assertEquals(1, jobKeys.size(), \"Number of jobs expected in default group was 1 \"); // job should have been left in place, because it is non-durable\n        assertEquals(0, triggerKeys.size(), \"Number of triggers expected in default group was 0 \");\n\n        sched.shutdown(true);\n    }\n\n    @Test\n    void testDurableStorageFunctions() throws Exception {\n        Scheduler sched = createScheduler(\"testDurableStorageFunctions\", 2);\n        try {\n            // test basic storage functions of scheduler...\n\n            JobDetail job = newJob()\n                    .ofType(TestJob.class)\n                    .withIdentity(\"j1\")\n                    .storeDurably()\n                    .build();\n\n            assertFalse(sched.checkExists(jobKey(\"j1\")), \"Unexpected existence of job named 'j1'.\");\n\n            sched.addJob(job, false);\n\n            assertTrue(sched.checkExists(jobKey(\"j1\")), \"Unexpected non-existence of job named 'j1'.\");\n\n            JobDetail nonDurableJob = newJob()\n                    .ofType(TestJob.class)\n                    .withIdentity(\"j2\")\n                    .build();\n\n            try {\n                sched.addJob(nonDurableJob, false);\n                fail(\"Storage of non-durable job should not have succeeded.\");\n            }\n            catch(SchedulerException expected) {\n                assertFalse(sched.checkExists(jobKey(\"j2\")), \"Unexpected existence of job named 'j2'.\");\n            }\n\n            sched.addJob(nonDurableJob, false, true);\n\n            assertTrue(sched.checkExists(jobKey(\"j2\")), \"Unexpected non-existence of job named 'j2'.\");\n        } finally {\n            sched.shutdown(true);\n        }\n    }\n\n    @Test\n    void testShutdownWithSleepReturnsAfterAllThreadsAreStopped() throws Exception {\n      Map<Thread, StackTraceElement[]> allThreadsStart = Thread.getAllStackTraces();\n      int threadPoolSize = 5;\n      Scheduler scheduler = createScheduler(\"testShutdownWithSleepReturnsAfterAllThreadsAreStopped\", threadPoolSize);\n      \n      Thread.sleep(500L);\n      \n      Map<Thread, StackTraceElement[]> allThreadsRunning = Thread.getAllStackTraces();\n\n      scheduler.shutdown( true );\n      \n      Thread.sleep(200L);\n\n      Map<Thread, StackTraceElement[]> allThreadsEnd = Thread.getAllStackTraces();\n      Set<Thread> endingThreads = new HashSet<Thread>(allThreadsEnd.keySet());\n      // remove all preexisting threads from the set\n      for(Thread t: allThreadsStart.keySet()) {\n        allThreadsEnd.remove(t);\n      }\n      // remove threads that are known artifacts of the test\n      for(Thread t: endingThreads) {\n        if(t.getName().contains(\"derby\") && t.getThreadGroup().getName().contains(\"derby\")) {\n          allThreadsEnd.remove(t);\n        }\n        if(t.getThreadGroup() != null && t.getThreadGroup().getName().equals(\"system\")) {\n          allThreadsEnd.remove(t);\n          \n        }\n        if(t.getThreadGroup() != null && t.getThreadGroup().getName().equals(\"main\")) {\n          allThreadsEnd.remove(t);\n        }\n      }\n      if(!allThreadsEnd.isEmpty()) {\n        // log the additional threads\n        for(Thread t: allThreadsEnd.keySet()) {\n          System.out.println(\"*** Found additional thread: \" + t.getName() + \" (of type \" + t.getClass().getName() +\")  in group: \" + t.getThreadGroup().getName() + \" with parent group: \" + (t.getThreadGroup().getParent() == null ? \"-none-\" : t.getThreadGroup().getParent().getName()));\n        }          \n        // log all threads that were running before shutdown\n        for(Thread t: allThreadsRunning.keySet()) {\n          System.out.println(\"- Test runtime thread: \" + t.getName() + \" (of type \" + t.getClass().getName() +\")  in group: \" + (t.getThreadGroup() == null ? \"-none-\" : (t.getThreadGroup().getName() + \" with parent group: \" + (t.getThreadGroup().getParent() == null ? \"-none-\" : t.getThreadGroup().getParent().getName()))));\n        }          \n      }\n        assertEquals(0, allThreadsEnd.size(), \"Found unexpected new threads (see console output for listing)\");\n    }\n\n    @Test\n    void testAbilityToFireImmediatelyWhenStartedBefore() throws Exception {\n    \t\n\t\tList<Long> jobExecTimestamps = Collections.synchronizedList(new ArrayList<Long>());\n\t\tCyclicBarrier barrier = new CyclicBarrier(2);\n    \t\n        Scheduler sched = createScheduler(\"testAbilityToFireImmediatelyWhenStartedBefore\", 5);\n        sched.getContext().put(BARRIER, barrier);\n        sched.getContext().put(DATE_STAMPS, jobExecTimestamps);\n        sched.start();\n        \n        Thread.yield();\n        \n\t\tJobDetail job1 = JobBuilder.newJob(TestJobWithSync.class).withIdentity(\"job1\").build();\n\t\tTrigger trigger1 = TriggerBuilder.newTrigger().forJob(job1).build(); \n\t\t\n\t\tlong sTime = System.currentTimeMillis();\n\t\t\n\t\tsched.scheduleJob(job1, trigger1);\n\t\t\n\t    barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n\n\t    sched.shutdown(true);\n\n\t\tlong fTime = jobExecTimestamps.get(0);\n\t\t\n\t\tassertTrue((fTime - sTime  < 7000L), \"Immediate trigger did not fire within a reasonable amount of time.\");  // This is dangerously subjective!  but what else to do?\n    }\n\n    @Test\n    void testAbilityToFireImmediatelyWhenStartedBeforeWithTriggerJob() throws Exception {\n    \t\n\t\tList<Long> jobExecTimestamps = Collections.synchronizedList(new ArrayList<Long>());\n\t\tCyclicBarrier barrier = new CyclicBarrier(2);\n    \t\n        Scheduler sched = createScheduler(\"testAbilityToFireImmediatelyWhenStartedBeforeWithTriggerJob\", 5);\n        sched.getContext().put(BARRIER, barrier);\n        sched.getContext().put(DATE_STAMPS, jobExecTimestamps);\n\n        sched.start();\n        \n        Thread.yield();\n\n        JobDetail job1 = JobBuilder.newJob(TestJobWithSync.class).withIdentity(\"job1\").storeDurably().build();\n\t\tsched.addJob(job1, false);\n\t\t\n\t\tlong sTime = System.currentTimeMillis();\n\t\t\n\t\tsched.triggerJob(job1.getKey());\n\t\t\n\t    barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n\n\t    sched.shutdown(true);\n\n\t\tlong fTime = jobExecTimestamps.get(0);\n\t\t\n\t\tassertTrue((fTime - sTime  < 7000L), \"Immediate trigger did not fire within a reasonable amount of time.\");  // This is dangerously subjective!  but what else to do?\n    }\n\n    @Test\n    void testAbilityToFireImmediatelyWhenStartedAfter() throws Exception {\n    \t\n\t\tList<Long> jobExecTimestamps = Collections.synchronizedList(new ArrayList<Long>());\n\t\tCyclicBarrier barrier = new CyclicBarrier(2);\n    \t\n        Scheduler sched = createScheduler(\"testAbilityToFireImmediatelyWhenStartedAfter\", 5);\n        sched.getContext().put(BARRIER, barrier);\n        sched.getContext().put(DATE_STAMPS, jobExecTimestamps);\n        \n\t\tJobDetail job1 = JobBuilder.newJob(TestJobWithSync.class).withIdentity(\"job1\").build();\n\t\tTrigger trigger1 = TriggerBuilder.newTrigger().forJob(job1).build(); \n\t\t\n\t\tlong sTime = System.currentTimeMillis();\n\t\t\n\t\tsched.scheduleJob(job1, trigger1);\n        sched.start();\n\t\t\n\t    barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n\t    \n\t    sched.shutdown(true);\n\n\t\tlong fTime = jobExecTimestamps.get(0);\n\t\t\n\t\tassertTrue((fTime - sTime  < 7000L), \"Immediate trigger did not fire within a reasonable amount of time.\");  // This is dangerously subjective!  but what else to do?\n    }\n\n    @Test\n\tvoid testScheduleMultipleTriggersForAJob() throws SchedulerException {\n\n\t\t\n\t\tJobDetail job = newJob(TestJob.class).withIdentity(\"job1\", \"group1\").build();\n\t\tTrigger trigger1 = newTrigger()\n\t\t\t\t.withIdentity(\"trigger1\", \"group1\")\n\t\t\t\t.startNow()\n\t\t\t\t.withSchedule(\n\t\t\t\t\t\tSimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)\n\t\t\t\t\t\t\t\t.repeatForever())\n\t\t\t\t.build();\n\t\tTrigger trigger2 = newTrigger()\n\t\t\t\t.withIdentity(\"trigger2\", \"group1\")\n\t\t\t\t.startNow()\n\t\t\t\t.withSchedule(\n\t\t\t\t\t\tSimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)\n\t\t\t\t\t\t\t\t.repeatForever())\n\t\t\t\t.build();\n\t\tSet<Trigger> triggersForJob = new HashSet<Trigger>(); \n\t\ttriggersForJob.add(trigger1);\n\t\ttriggersForJob.add(trigger2);\n\t\t\n\t\tScheduler sched = createScheduler(\"testScheduleMultipleTriggersForAJob\", 5);\n\t\tsched.scheduleJob(job,triggersForJob, true);\n\t\t\n\t\tList<? extends Trigger> triggersOfJob = sched.getTriggersOfJob(job.getKey());\n\t\tassertEquals(2,triggersOfJob.size());\n\t\tassertTrue(triggersOfJob.contains(trigger1));\n\t\tassertTrue(triggersOfJob.contains(trigger2));\n\t\t\n\t\tsched.shutdown(true);\n\t}\n\n    @Test\n    void testShutdownWithoutWaitIsUnclean() throws Exception {\n        CyclicBarrier barrier = new CyclicBarrier(2);\n        Scheduler scheduler = createScheduler(\"testShutdownWithoutWaitIsUnclean\", 8);\n        try {\n            scheduler.getContext().put(BARRIER, barrier);\n            scheduler.start();\n            scheduler.addJob(newJob().ofType(UncleanShutdownJob.class).withIdentity(\"job\").storeDurably().build(), false);\n            scheduler.scheduleJob(newTrigger().forJob(\"job\").startNow().build());\n            while (scheduler.getCurrentlyExecutingJobs().isEmpty()) {\n                Thread.sleep(50);\n            }\n        } finally {\n            scheduler.shutdown(false);\n        }\n        \n        barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n        \n        Thread jobThread = (Thread) scheduler.getContext().get(JOB_THREAD);\n        jobThread.join(TimeUnit.SECONDS.toMillis(TEST_TIMEOUT_SECONDS));\n    }\n    \n    public static class UncleanShutdownJob implements Job {\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            try {\n                SchedulerContext schedulerContext = context.getScheduler().getContext();\n                schedulerContext.put(JOB_THREAD, Thread.currentThread());\n                CyclicBarrier barrier =  (CyclicBarrier) schedulerContext.get(BARRIER);\n                barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n            } catch (Throwable e) {\n                e.printStackTrace();\n                throw new AssertionError(\"Await on barrier was interrupted: \" + e.toString());\n            } \n        }\n    }\n\n    @Test\n    void testShutdownWithWaitIsClean() throws Exception {\n        final AtomicBoolean shutdown = new AtomicBoolean(false);\n        List<Long> jobExecTimestamps = Collections.synchronizedList(new ArrayList<Long>());\n        CyclicBarrier barrier = new CyclicBarrier(2);\n        final Scheduler scheduler = createScheduler(\"testShutdownWithWaitIsClean\", 8);\n        try {\n            scheduler.getContext().put(BARRIER, barrier);\n            scheduler.getContext().put(DATE_STAMPS, jobExecTimestamps);\n            scheduler.start();\n            scheduler.addJob(newJob().ofType(TestJobWithSync.class).withIdentity(\"job\").storeDurably().build(), false);\n            scheduler.scheduleJob(newTrigger().forJob(\"job\").startNow().build());\n            while (scheduler.getCurrentlyExecutingJobs().isEmpty()) {\n                Thread.sleep(50);\n            }\n        } finally {\n            Thread t = new Thread() {\n                @Override\n                public void run() {\n                    try {\n                        scheduler.shutdown(true);\n                        shutdown.set(true);\n                    } catch (SchedulerException ex) {\n                        throw new RuntimeException(ex);\n                    }\n                }\n            };\n            t.start();\n            Thread.sleep(1000);\n            assertFalse(shutdown.get());\n            barrier.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);\n            t.join();\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/AnnualCalendarTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.calendar.AnnualCalendar;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n\n/**\n * Unit test for AnnualCalendar serialization backwards compatibility.\n */\npublic class AnnualCalendarTest extends SerializationTestSupport {\n    private static final String[] VERSIONS = new String[] {\"1.5.1\"};\n    \n    private static final TimeZone EST_TIME_ZONE = TimeZone.getTimeZone(\"America/New_York\"); \n\n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @Override\n    protected Object getTargetObject() {\n        AnnualCalendar c = new AnnualCalendar();\n        \n        c.setDescription(\"description\");\n        \n        Calendar cal = Calendar.getInstance(EST_TIME_ZONE, Locale.US); \n        cal.clear();\n        cal.set(2005, Calendar.JANUARY, 20, 10, 5, 15);\n        \n        c.setDayExcluded(cal, true);\n        \n        return c;\n    }\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        AnnualCalendar targetCalendar = (AnnualCalendar)target;\n        AnnualCalendar deserializedCalendar = (AnnualCalendar)deserialized;\n        \n        assertNotNull(deserializedCalendar);\n        assertEquals(targetCalendar.getDescription(), deserializedCalendar.getDescription());\n        assertEquals(targetCalendar.getDaysExcluded(), deserializedCalendar.getDaysExcluded());\n        assertNull(deserializedCalendar.getTimeZone());\n    }\n\n    /**\n     * Tests if method <code>setDaysExcluded</code> protects the property daysExcluded against nulling.\n     * See: QUARTZ-590\n     */\n    @Test\n    void testDaysExcluded() {\n\t\tAnnualCalendar annualCalendar = new AnnualCalendar();\n\t\t\n\t\tannualCalendar.setDaysExcluded(null);\n\t\t\n\t\tassertNotNull(annualCalendar.getDaysExcluded(),\"Annual calendar daysExcluded property should have been set to empty ArrayList, not null.\");\n    }\n\n    /**\n     * Tests the parameter <code>exclude</code> in a method <code>setDaysExcluded</code>\n     * of class <code>org.quartz.impl.calendar.AnnualCalendar</code>\n     */\n    @Test\n    void testExclude() {\n        AnnualCalendar annualCalendar = new AnnualCalendar();\n        Calendar day = Calendar.getInstance();\n\n        day.set(Calendar.MONTH, 9);\n        day.set(Calendar.DAY_OF_MONTH, 15);\n        annualCalendar.setDayExcluded(day, false);\n\n        assertFalse(annualCalendar.isDayExcluded(day), \"The day 15 October is not expected to be excluded but it is\");\n\n        day.set(Calendar.MONTH, 9);\n        day.set(Calendar.DAY_OF_MONTH, 15);\n        annualCalendar.setDayExcluded((Calendar) day.clone(), true);\n\n        day.set(Calendar.MONTH, 10);\n        day.set(Calendar.DAY_OF_MONTH, 12);\n        annualCalendar.setDayExcluded((Calendar) day.clone(), true);\n\n        day.set(Calendar.MONTH, 8);\n        day.set(Calendar.DAY_OF_MONTH, 1);\n        annualCalendar.setDayExcluded((Calendar) day.clone(), true);\n\n        assertTrue(annualCalendar.isDayExcluded(day), \"The day 15 October is expected to be excluded but it is not\");\n\n        day.set(Calendar.MONTH, 9);\n        day.set(Calendar.DAY_OF_MONTH, 15);\n        annualCalendar.setDayExcluded((Calendar) day.clone(), false);\n\n        assertFalse(annualCalendar.isDayExcluded(day), \"The day 15 October is not expected to be excluded but it is\");\n    }\n\n    /**\n     * QUARTZ-679 Test if the annualCalendar works over years\n     */\n    @Test\n    void testDaysExcludedOverTime() {\n        AnnualCalendar annualCalendar = new AnnualCalendar();\n        Calendar day = Calendar.getInstance();\n        \n        day.set(Calendar.MONTH, Calendar.JUNE);\n        day.set(Calendar.YEAR, 2005);\n        day.set(Calendar.DAY_OF_MONTH, 23);\n        \n        annualCalendar.setDayExcluded((Calendar) day.clone(), true);\n        \n    \tday.set(Calendar.YEAR, 2008);\n    \tday.set(Calendar.MONTH, Calendar.FEBRUARY);\n    \tday.set(Calendar.DAY_OF_MONTH, 1);\n    \tannualCalendar.setDayExcluded((Calendar) day.clone(), true);\n \n    \tassertTrue(annualCalendar.isDayExcluded(day), \"The day 1 February is expected to be excluded but it is not\");\n    }\n\n    /**\n     * Part 2 of the tests of QUARTZ-679\n     */\n    @Test\n    void testRemoveInTheFuture() {\n        AnnualCalendar annualCalendar = new AnnualCalendar();\n        Calendar day = Calendar.getInstance();\n        \n        day.set(Calendar.MONTH, Calendar.JUNE);\n        day.set(Calendar.YEAR, 2005);\n        day.set(Calendar.DAY_OF_MONTH, 23);\n        \n        annualCalendar.setDayExcluded((Calendar) day.clone(), true);\n\n    \t// Trying to remove the 23th of June\n        day.set(Calendar.MONTH, Calendar.JUNE);\n        day.set(Calendar.YEAR, 2008);\n        day.set(Calendar.DAY_OF_MONTH, 23);\n        annualCalendar.setDayExcluded((Calendar) day.clone(), false);\n\n        assertFalse(annualCalendar.isDayExcluded(day), \"The day 23 June is not expected to be excluded but it is\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/CalendarIntervalTriggerTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.*;\n\n\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.TimeZone;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.calendar.BaseCalendar;\nimport org.quartz.impl.triggers.CalendarIntervalTriggerImpl;\n\n/**\n * Unit tests for DateIntervalTrigger.\n */\npublic class CalendarIntervalTriggerTest  extends SerializationTestSupport {\n    \n    private static final String[] VERSIONS = new String[] {\"2.0\"};\n\n    @Test\n    void testQTZ331FireTimeAfterBoundary() {\n        Calendar start = Calendar.getInstance();\n        start.clear();\n        start.set(2013, Calendar.FEBRUARY, 15);\n\n        Date startTime = start.getTime();\n        start.add(Calendar.DAY_OF_MONTH, 1);\n        Date triggerTime = start.getTime();\n\n        CalendarIntervalTriggerImpl trigger = new CalendarIntervalTriggerImpl(\"test\", startTime, null, IntervalUnit.DAY, 1);\n        assertThat(trigger.getFireTimeAfter(startTime), equalTo(triggerTime));\n\n\n        Date after = new Date(start.getTimeInMillis() - 500);\n        assertThat(trigger.getFireTimeAfter(after), equalTo(triggerTime));\n    }\n\n    void testQTZ330DaylightSavingsCornerCase() {\n        TimeZone edt = TimeZone.getTimeZone(\"America/New_York\");\n\n        Calendar start = Calendar.getInstance();\n        start.clear();\n        start.setTimeZone(edt);\n        start.set(2012, Calendar.MARCH, 16, 2, 30, 0);\n\n        Calendar after = Calendar.getInstance();\n        after.clear();\n        after.setTimeZone(edt);\n        after.set(2013, Calendar.APRIL, 19, 2, 30, 0);\n\n        BaseCalendar baseCalendar = new BaseCalendar(edt);\n\n        CalendarIntervalTriggerImpl intervalTrigger = new CalendarIntervalTriggerImpl(\"QTZ-330\", start.getTime(), null, DateBuilder.IntervalUnit.DAY, 1);\n        intervalTrigger.setTimeZone(edt);\n        intervalTrigger.setPreserveHourOfDayAcrossDaylightSavings(true);\n        intervalTrigger.computeFirstFireTime(baseCalendar);\n\n        Date fireTime = intervalTrigger.getFireTimeAfter(after.getTime());\n        assertThat(fireTime.after(after.getTime()), is(true));\n    }\n\n    @Test\n    void testYearlyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.YEAR);\n        yearlyTrigger.setRepeatInterval(2); // every two years;\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2009, Calendar.JUNE, 1, 9, 30, 17); // jump 4 years (2 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 4);\n        Date secondTime = fireTimes.get(2); // get the third fire time\n        \n        assertEquals(targetCalendar.getTime(), secondTime, \"Year increment result not as expected.\");\n    }\n\n    @Test\n    void testMonthlyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MONTH);\n        yearlyTrigger.setRepeatInterval(5); // every five months\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.MONTH, 25); // jump 25 five months (5 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 6);\n        Date fifthTime = fireTimes.get(5); // get the sixth fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Month increment result not as expected.\");\n    }\n    @Test\n    void testWeeklyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.WEEK);\n        yearlyTrigger.setRepeatInterval(6); // every six weeks\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 7 * 6 * 4); // jump 24 weeks (4 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 7);\n        Date fifthTime = fireTimes.get(4); // get the fifth fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Week increment result not as expected.\");\n    }\n    @Test\n    void testDailyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(90); // every ninety days\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 360); // jump 360 days (4 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n        Date fifthTime = fireTimes.get(4); // get the fifth fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Day increment result not as expected.\");\n    }\n    @Test\n    void testHourlyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.HOUR);\n        yearlyTrigger.setRepeatInterval(100); // every 100 hours\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.HOUR, 400); // jump 400 hours (4 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 6);\n        Date fifthTime = fireTimes.get(4); // get the fifth fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Hour increment result not as expected.\");\n    }\n    @Test\n    void testMinutelyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\n        yearlyTrigger.setRepeatInterval(100); // every 100 minutes\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.MINUTE, 400); // jump 400 minutes (4 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 6);\n        Date fifthTime = fireTimes.get(4); // get the fifth fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Minutes increment result not as expected.\");\n    }\n    @Test\n    void testSecondlyIntervalGetFireTimeAfter() {\n\n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl yearlyTrigger = new CalendarIntervalTriggerImpl();\n        yearlyTrigger.setStartTime(startCalendar.getTime());\n        yearlyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.SECOND);\n        yearlyTrigger.setRepeatInterval(100); // every 100 seconds\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.set(2005, Calendar.JUNE, 1, 9, 30, 17);\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.SECOND, 400); // jump 400 seconds (4 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(yearlyTrigger, null, 6);\n        Date fifthTime = fireTimes.get(4); // get the third fire time\n\n        assertEquals(targetCalendar.getTime(), fifthTime, \"Seconds increment result not as expected.\");\n    }\n    @Test\n    void testDaylightSavingsTransitions() {\n\n        // Pick a day before a spring daylight savings transition...\n        \n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2010, Calendar.MARCH, 12, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(5); // every 5 days\n        \n        Calendar targetCalendar = Calendar.getInstance();\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 10); // jump 10 days (2 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        List<Date> fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n        Date testTime = fireTimes.get(2); // get the third fire time\n\n        assertEquals(targetCalendar.getTime(), testTime, \"Day increment result not as expected over spring 2010 daylight savings transition.\");\n\n        // And again, Pick a day before a spring daylight savings transition... (QTZ-240)\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.set(2011, Calendar.MARCH, 12, 1, 0, 0);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(1); // every day\n        \n        targetCalendar = Calendar.getInstance();\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 2); // jump 2 days (2 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n        testTime = fireTimes.get(2); // get the third fire time\n\n        assertEquals(targetCalendar.getTime(), testTime, \"Day increment result not as expected over spring 2011 daylight savings transition.\");\n        \n        // And again, Pick a day before a spring daylight savings transition... (QTZ-240) - and prove time of day is not preserved without setPreserveHourOfDayAcrossDaylightSavings(true)\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.setTimeZone(TimeZone.getTimeZone(\"CET\"));\n        startCalendar.set(2011, Calendar.MARCH, 26, 4, 0, 0);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(1); // every day\n        dailyTrigger.setTimeZone(TimeZone.getTimeZone(\"EST\"));\n        \n        targetCalendar = Calendar.getInstance();\n        targetCalendar.setTimeZone(TimeZone.getTimeZone(\"CET\"));\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 2); // jump 2 days (2 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n\n\t\ttestTime = fireTimes.get(2); // get the third fire time\n\n        Calendar testCal = Calendar.getInstance(TimeZone.getTimeZone(\"CET\"));\n        testCal.setTimeInMillis(testTime.getTime());\n\n        assertNotEquals(targetCalendar.get(Calendar.HOUR_OF_DAY), testCal.get(Calendar.HOUR_OF_DAY), \"Day increment time-of-day result not as expected over spring 2011 daylight savings transition.\");\n        \n        // And again, Pick a day before a spring daylight savings transition... (QTZ-240) - and prove time of day is preserved with setPreserveHourOfDayAcrossDaylightSavings(true)\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.setTimeZone(TimeZone.getTimeZone(\"CET\"));\n        startCalendar.set(2011, Calendar.MARCH, 26, 4, 0, 0);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(1); // every day\n        dailyTrigger.setTimeZone(TimeZone.getTimeZone(\"CET\"));\n        dailyTrigger.setPreserveHourOfDayAcrossDaylightSavings(true);\n        \n        targetCalendar = Calendar.getInstance();\n        targetCalendar.setTimeZone(TimeZone.getTimeZone(\"CET\"));\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 2); // jump 2 days (2 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n\n\t\ttestTime = fireTimes.get(2); // get the third fire time\n\n        testCal = Calendar.getInstance(TimeZone.getTimeZone(\"CET\"));\n        testCal.setTimeInMillis(testTime.getTime());\n\n        assertEquals(targetCalendar.get(Calendar.HOUR_OF_DAY), testCal.get(Calendar.HOUR_OF_DAY), \"Day increment time-of-day result not as expected over spring 2011 daylight savings transition.\");\n        \n        // Pick a day before a fall daylight savings transition...\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.set(2010, Calendar.OCTOBER, 31, 9, 30, 17);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(5); // every 5 days\n        \n        targetCalendar = Calendar.getInstance();\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 15); // jump 15 days (3 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n        testTime = (Date) fireTimes.get(3); // get the fourth fire time\n\n        assertEquals(targetCalendar.getTime(), testTime, \"Day increment result not as expected over fall 2010 daylight savings transition.\");\n        \n        // And again, Pick a day before a fall daylight savings transition...  (QTZ-240)\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.setTimeZone(TimeZone.getTimeZone(\"CEST\"));\n        startCalendar.set(2011, Calendar.OCTOBER, 29, 1, 30, 00);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(1); // every day\n        dailyTrigger.setTimeZone(TimeZone.getTimeZone(\"EST\"));\n\n        targetCalendar = Calendar.getInstance();\n        targetCalendar.setTimeZone(TimeZone.getTimeZone(\"CEST\"));\n        targetCalendar.setTime(startCalendar.getTime());\n        targetCalendar.setLenient(true);\n        targetCalendar.add(Calendar.DAY_OF_YEAR, 3); // jump 3 days (3 intervals)\n        targetCalendar.clear(Calendar.MILLISECOND);\n\n        fireTimes = TriggerUtils.computeFireTimes(dailyTrigger, null, 6);\n        testTime = (Date) fireTimes.get(3); // get the fourth fire time\n\n        assertEquals(targetCalendar.getTime(), testTime, \"Day increment result not as expected over fall 2011 daylight savings transition.\");\n    }\n\n    @Test\n    void testFinalFireTimes() {\n\n        \n        Calendar startCalendar = Calendar.getInstance();\n        startCalendar.set(2010, Calendar.MARCH, 12, 9, 0, 0);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        CalendarIntervalTriggerImpl dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.DAY);\n        dailyTrigger.setRepeatInterval(5); // every 5 days\n        \n        Calendar endCalendar = Calendar.getInstance();\n        endCalendar.setTime(startCalendar.getTime());\n        endCalendar.setLenient(true);\n        endCalendar.add(Calendar.DAY_OF_YEAR, 10); // jump 10 days (2 intervals)\n        endCalendar.clear(Calendar.MILLISECOND);\n        dailyTrigger.setEndTime(endCalendar.getTime());\n\n        Date testTime = dailyTrigger.getFinalFireTime();\n\n        assertEquals(endCalendar.getTime(), testTime, \"Final fire time not computed correctly for day interval.\");\n\n        \n        startCalendar = Calendar.getInstance();\n        startCalendar.set(2010, Calendar.MARCH, 12, 9, 0, 0);\n        startCalendar.clear(Calendar.MILLISECOND);\n\n        dailyTrigger = new CalendarIntervalTriggerImpl();\n        dailyTrigger.setStartTime(startCalendar.getTime());\n        dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\n        dailyTrigger.setRepeatInterval(5); // every 5 minutes\n        \n        endCalendar = Calendar.getInstance();\n        endCalendar.setTime(startCalendar.getTime());\n        endCalendar.setLenient(true);\n        endCalendar.add(Calendar.DAY_OF_YEAR, 15); // jump 15 days \n        endCalendar.add(Calendar.MINUTE,-2); // back up two minutes\n        endCalendar.clear(Calendar.MILLISECOND);\n        dailyTrigger.setEndTime(endCalendar.getTime());\n\n        testTime = dailyTrigger.getFinalFireTime();\n\n        assertTrue((endCalendar.getTime().after(testTime)), \"Final fire time not computed correctly for minutely interval.\");\n\n        endCalendar.add(Calendar.MINUTE,-3); // back up three more minutes\n\n        assertEquals(endCalendar.getTime(), testTime, \"Final fire time not computed correctly for minutely interval.\");\n    }\n\n    @Test\n    void testMisfireInstructionValidity() throws ParseException {\n        CalendarIntervalTriggerImpl trigger = new CalendarIntervalTriggerImpl();\n\n        try {\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_SMART_POLICY);\n            trigger.setMisfireInstruction(CalendarIntervalTriggerImpl.MISFIRE_INSTRUCTION_DO_NOTHING);\n            trigger.setMisfireInstruction(CalendarIntervalTriggerImpl.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);\n        }\n        catch(Exception e) {\n            fail(\"Unexpected exception while setting misfire instruction.\");\n        }\n        \n        try {\n            trigger.setMisfireInstruction(CalendarIntervalTriggerImpl.MISFIRE_INSTRUCTION_DO_NOTHING + 1);\n            \n            fail(\"Expected exception while setting invalid misfire instruction but did not get it.\");\n        }\n        catch(Exception e) {\n        }\n    }\n    \n    @Override\n    protected Object getTargetObject() throws Exception {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"A\", \"B\");\n        \n        CalendarIntervalTriggerImpl t = new CalendarIntervalTriggerImpl();\n        t.setName(\"test\");\n        t.setGroup(\"testGroup\");\n        t.setCalendarName(\"MyCalendar\");\n        t.setDescription(\"CronTriggerDesc\");\n        t.setJobDataMap(jobDataMap);\n        t.setRepeatInterval(5);\n        t.setRepeatIntervalUnit(IntervalUnit.DAY);\n\n        return t;    \n    }\n\n\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        CalendarIntervalTriggerImpl targetCalTrigger = (CalendarIntervalTriggerImpl)target;\n        CalendarIntervalTriggerImpl deserializedCalTrigger = (CalendarIntervalTriggerImpl)deserialized;\n\n        assertNotNull(deserializedCalTrigger);\n        assertEquals(targetCalTrigger.getName(), deserializedCalTrigger.getName());\n        assertEquals(targetCalTrigger.getGroup(), deserializedCalTrigger.getGroup());\n        assertEquals(targetCalTrigger.getJobName(), deserializedCalTrigger.getJobName());\n        assertEquals(targetCalTrigger.getJobGroup(), deserializedCalTrigger.getJobGroup());\n//        assertEquals(targetCronTrigger.getStartTime(), deserializedCronTrigger.getStartTime());\n        assertEquals(targetCalTrigger.getEndTime(), deserializedCalTrigger.getEndTime());\n        assertEquals(targetCalTrigger.getCalendarName(), deserializedCalTrigger.getCalendarName());\n        assertEquals(targetCalTrigger.getDescription(), deserializedCalTrigger.getDescription());\n        assertEquals(targetCalTrigger.getJobDataMap(), deserializedCalTrigger.getJobDataMap());\n        assertEquals(targetCalTrigger.getRepeatInterval(), deserializedCalTrigger.getRepeatInterval());\n        assertEquals(targetCalTrigger.getRepeatIntervalUnit(), deserializedCalTrigger.getRepeatIntervalUnit());\n        \n    }\n    \n    // execute with version number to generate a new version's serialized form\n    public static void main(String[] args) throws Exception {\n        new CalendarIntervalTriggerTest().writeJobDataFile(\"2.0\");\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/CronExpressionTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.*;\nimport java.text.ParseException;\nimport java.util.*;\nimport java.util.Calendar;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\npublic class CronExpressionTest extends SerializationTestSupport {\n    private static final String[] VERSIONS = new String[] {\"1.5.2\"};\n\n    private static final TimeZone EST_TIME_ZONE = TimeZone.getTimeZone(\"US/Eastern\"); \n\n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @Override\n    protected Object getTargetObject() throws ParseException {\n        CronExpression cronExpression = new CronExpression(\"0 15 10 * * ? 2005\");\n        cronExpression.setTimeZone(EST_TIME_ZONE);\n        \n        return cronExpression;\n    }\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        CronExpression targetCronExpression = (CronExpression)target;\n        CronExpression deserializedCronExpression = (CronExpression)deserialized;\n        \n        assertNotNull(deserializedCronExpression);\n        assertEquals(targetCronExpression.getCronExpression(), deserializedCronExpression.getCronExpression());\n        assertEquals(targetCronExpression.getTimeZone(), deserializedCronExpression.getTimeZone());\n    }\n\n    void testTooManyTokens() throws Exception {\n        try {\n            new CronExpression(\"0 15 10 * * ? 2005 *\"); // too many tokens/terms in expression\n            fail(\"Expected ParseException did not occur for invalid expression\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().contains(\"too many\"),\n                    \"Incorrect ParseException thrown\");\n        }\n\n    }\n\n    /*\n     * Test method for 'org.quartz.CronExpression.isSatisfiedBy(Date)'.\n     */\n    @Test\n    void testIsSatisfiedBy() throws Exception {\n        CronExpression cronExpression = new CronExpression(\"0 15 10 * * ? 2005\");\n        \n        Calendar cal = Calendar.getInstance();\n        \n        cal.set(2005, Calendar.JUNE, 1, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(Calendar.DAY_OF_MONTH, 30);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(Calendar.YEAR, 2006);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.JUNE, 1, 10, 16, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.JUNE, 1, 10, 14, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test for March\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.MARCH, 1, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(Calendar.DAY_OF_MONTH, 31);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.MARCH, 1, 10, 16, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.MARCH, 1, 10, 14, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test for February\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.FEBRUARY, 1, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(Calendar.DAY_OF_MONTH, 28);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.FEBRUARY, 1, 10, 16, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal = Calendar.getInstance();\n        cal.set(2005, Calendar.FEBRUARY, 1, 10, 14, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test specific day of month\n        cronExpression = new CronExpression(\"0 15 10 12 * ? 2005\");\n        cal.set(2005, Calendar.DECEMBER, 12, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 11, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 13, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n    }\n\n    @Test\n    void testIsSatisfiedByLastDayOfMonth() throws Exception {\n        Calendar cal = Calendar.getInstance();\n\n        // Test months with 31 days\n        CronExpression cronExpression = new CronExpression(\"0 15 10 L * ? 2005\");\n        cal.set(2005, Calendar.DECEMBER, 31, 10, 15, 0); // December has 31 days\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 30, 10, 15, 0); // Not the last day\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test months with 30 days\n        cronExpression = new CronExpression(\"0 15 10 L * ? 2005\");\n        cal.set(2005, Calendar.SEPTEMBER, 30, 10, 15, 0); // September has 30 days\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.SEPTEMBER, 29, 10, 15, 0); // Not the last day\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test February (non-leap year)\n        cronExpression = new CronExpression(\"0 15 10 L 2 ? 2005\");\n        cal.set(2005, Calendar.FEBRUARY, 28, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.FEBRUARY, 27, 10, 15, 0); // Not the last day\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test February (leap year)\n        cronExpression = new CronExpression(\"0 15 10 L 2 ? 2004\");\n        cal.set(2004, Calendar.FEBRUARY, 29, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2004, Calendar.FEBRUARY, 28, 10, 15, 0); // Not the last day\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n    }\n\n    @Test\n    void testIsSatisfiedByLastDayOfMonthWithOffset() throws Exception {\n        Calendar cal = Calendar.getInstance();\n\n        // Test months with 31 days\n        CronExpression cronExpression = new CronExpression(\"0 15 10 L-2 * ? 2005\");\n        cal.set(2005, Calendar.DECEMBER, 29, 10, 15, 0); // December has 31 days, L-2 = 29th\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 28, 10, 15, 0); // Not L-2\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 30, 10, 15, 0); // Not L-2\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.DECEMBER, 31, 10, 15, 0); // Not L-2\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test months with 30 days\n        cronExpression = new CronExpression(\"0 15 10 L-1 * ? 2005\");\n        cal.set(2005, Calendar.SEPTEMBER, 29, 10, 15, 0); // September has 30 days, L-1 = 29th\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.SEPTEMBER, 27, 10, 15, 0); // Not L-1\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.SEPTEMBER, 28, 10, 15, 0); // Not L-1\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.SEPTEMBER, 30, 10, 15, 0); // Not L-1\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test February (non-leap year)\n        cronExpression = new CronExpression(\"0 15 10 L-3 2 ? 2005\");\n        cal.set(2005, Calendar.FEBRUARY, 25, 10, 15, 0); // February has 28 days in 2005, L-3 = 25th\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.FEBRUARY, 24, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.FEBRUARY, 26, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2005, Calendar.FEBRUARY, 28, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        // Test February (leap year)\n        cronExpression = new CronExpression(\"0 15 10 L-3 2 ? 2000\");\n        cal.set(2000, Calendar.FEBRUARY, 26, 10, 15, 0); // February has 29 days in 2000, L-3 = 26th\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2000, Calendar.FEBRUARY, 25, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2000, Calendar.FEBRUARY, 27, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2000, Calendar.FEBRUARY, 29, 10, 15, 0); // Not L-3\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n    }\n\n    @Test\n    void testLastDayOffset() throws Exception {\n        CronExpression cronExpression = new CronExpression(\"0 15 10 L-2 * ? 2010\");\n        \n        Calendar cal = Calendar.getInstance();\n        \n        cal.set(2010, Calendar.OCTOBER, 29, 10, 15, 0); // last day - 2\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 28, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.FEBRUARY, 26, 10, 15, 0); // last day - 2 for February\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.FEBRUARY, 25, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.JUNE, 28, 10, 15, 0); // last day - 2 for June\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.JUNE, 27, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cronExpression = new CronExpression(\"0 15 10 L-5W * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 26, 10, 15, 0); // last day - 5\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 25, 10, 15, 0); // not last day - 5\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.OCTOBER, 27, 10, 15, 0); // not last day - 5\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.SEPTEMBER, 24, 10, 15, 0); // last day - 5 (September has 30 days)\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.SEPTEMBER, 23, 10, 15, 0); // not last day - 5\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.SEPTEMBER, 25, 10, 15, 0); // not last day - 5\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cronExpression = new CronExpression(\"0 15 10 L-1 * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 30, 10, 15, 0); // last day - 1\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cronExpression = new CronExpression(\"0 15 10 L-1W * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 29, 10, 15, 0); // nearest weekday to last day - 1 (29th is a friday in 2010)\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cronExpression = new CronExpression(\"0 15 10 1,L * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 1, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 31, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 30, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.FEBRUARY, 1, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.FEBRUARY, 28, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.FEBRUARY, 27, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cronExpression = new CronExpression(\"0 15 10 L-1W,L-1 * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 29, 10, 15, 0); // nearest weekday to last day - 1 (29th is a friday in 2010)\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 30, 10, 15, 0); // last day - 1\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.FEBRUARY, 26, 10, 15, 0); // nearest weekday to last day - 1 (26th is a friday in 2010)\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.FEBRUARY, 27, 10, 15, 0); // last day - 1\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cronExpression = new CronExpression(\"0 15 10 2W,16 * ? 2010\");\n        \n        cal.set(2010, Calendar.OCTOBER, 1, 10, 15, 0); // nearest weekday to the 2nd of the month (1st is a friday in 2010)\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 2, 10, 15, 0);\n        assertFalse(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.OCTOBER, 16, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n        \n        cal.set(2010, Calendar.NOVEMBER, 2, 10, 15, 0); // 2nd is a Tuesday in November 2010\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n\n        cal.set(2010, Calendar.NOVEMBER, 16, 10, 15, 0);\n        assertTrue(cronExpression.isSatisfiedBy(cal.getTime()));\n    }\n\n    /*\n     * QUARTZ-571: Showing that expressions with months correctly serialize.\n     */\n    @Test\n    void testQuartz571() throws Exception {\n        CronExpression cronExpression = new CronExpression(\"19 15 10 4 Apr ? \");\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        ObjectOutputStream oos = new ObjectOutputStream(baos);\n        oos.writeObject(cronExpression);\n        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());\n        ObjectInputStream ois = new ObjectInputStream(bais);\n        CronExpression newExpression = (CronExpression) ois.readObject();\n\n        assertEquals(newExpression.getCronExpression(), cronExpression.getCronExpression());\n\n        // if broken, this will throw an exception\n        newExpression.getNextValidTimeAfter(new Date());\n    }\n\n    /**\n     * QTZ-259 : last day offset causes repeating fire time\n     * \n     */\n    @Test\n \tvoid testQtz259() throws Exception {\n \t\tCronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(\"0 0 0 L-2 * ? *\");\n \t\tTrigger trigger = TriggerBuilder.newTrigger().withIdentity(\"test\").withSchedule(schedBuilder).build();\n \t\t\t\t\n \t\tint i = 0;\n \t\tDate previousDate = trigger.getFireTimeAfter(new Date());\n \t\twhile (++i < 26) {\n \t\t\tDate date = trigger.getFireTimeAfter(previousDate);\n \t\t\tSystem.out.println(\"fireTime: \" + date + \", previousFireTime: \" + previousDate);\n            assertNotEquals(previousDate, date, \"Next fire time is the same as previous fire time!\");\n \t\t\tpreviousDate = date;\n \t\t}\n \t}\n    \n    /**\n     * QTZ-259 : last day offset causes repeating fire time\n     * \n     */\n    @Test\n \tvoid testQtz259LW() throws Exception {\n \t\tCronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(\"0 0 0 LW * ? *\");\n \t\tTrigger trigger = TriggerBuilder.newTrigger().withIdentity(\"test\").withSchedule(schedBuilder).build();\n \t\t\t\t\n \t\tint i = 0;\n \t\tDate pdate = trigger.getFireTimeAfter(new Date());\n \t\twhile (++i < 26) {\n \t\t\tDate date = trigger.getFireTimeAfter(pdate);\n \t\t\tSystem.out.println(\"fireTime: \" + date + \", previousFireTime: \" + pdate);\n            assertNotEquals(pdate, date, \"Next fire time is the same as previous fire time!\");\n \t\t\tpdate = date;\n \t\t}\n \t}\n \t\n    /*\n     * QUARTZ-574: Showing that storeExpressionVals correctly calculates the month number\n     */\n    @Test\n    void testQuartz574() {\n        try {\n            new CronExpression(\"* * * * Foo ? \");\n            fail(\"Expected ParseException did not fire for nonexistent month\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Invalid Month value:\"),\n                    \"Incorrect ParseException thrown\");\n        }\n\n        try {\n            new CronExpression(\"* * * * Jan-Foo ? \");\n            fail(\"Expected ParseException did not fire for nonexistent month\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Invalid Month value:\"),\n                    \"Incorrect ParseException thrown\");\n        }\n    }\n\n    @Test\n    void testQuartz621() {\n        try {\n            new CronExpression(\"0 0 * * * *\");\n            fail(\"Expected ParseException did not fire for wildcard day-of-month and day-of-week\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\"),\n                    \"Incorrect ParseException thrown\");\n        }\n        try {\n            new CronExpression(\"0 0 * 4 * *\");\n            fail(\"Expected ParseException did not fire for specified day-of-month and wildcard day-of-week\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\"),\n                    \"Incorrect ParseException thrown\");\n        }\n        try {\n            new CronExpression(\"0 0 * * * 4\");\n            fail(\"Expected ParseException did not fire for wildcard day-of-month and specified day-of-week\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\"),\n                    \"Incorrect ParseException thrown\");\n        }\n    }\n\n    @Test\n    void testQuartz640() throws ParseException {\n        try {\n            new CronExpression(\"0 43 9 ? * SAT,SUN,L\");\n            fail(\"Expected ParseException did not fire for L combined with other days of the week\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Support for specifying 'L' with other days of the week is not implemented\"),\n                    \"Incorrect ParseException thrown\");\n        }\n        try {\n            new CronExpression(\"0 43 9 ? * 6,7,L\");\n            fail(\"Expected ParseException did not fire for L combined with other days of the week\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"Support for specifying 'L' with other days of the week is not implemented\"),\n                    \"Incorrect ParseException thrown\");\n        }\n        try {\n            new CronExpression(\"0 43 9 ? * 5L\");\n        } catch(ParseException pe) {\n            fail(\"Unexpected ParseException thrown for supported '5L' expression.\");\n        }\n    }\n\n    @Test\n    void testQtz96() throws ParseException {\n        try {\n            new CronExpression(\"0/5 * * 32W 1 ?\");\n            fail(\"Expected ParseException did not fire for W with value larger than 31\");\n        } catch(ParseException pe) {\n            assertTrue(pe.getMessage().startsWith(\"The 'W' option does not make sense with values larger than\"),\n                    \"Incorrect ParseException thrown\");\n        }\n    }\n\n    void testQtz395_CopyConstructorMustPreserveTimeZone () throws ParseException {\n        TimeZone nonDefault = TimeZone.getTimeZone(\"Europe/Brussels\");\n        if (nonDefault.equals(TimeZone.getDefault())) {\n            nonDefault = EST_TIME_ZONE;\n        }\n        CronExpression cronExpression = new CronExpression(\"0 15 10 * * ? 2005\");\n        cronExpression.setTimeZone(nonDefault);\n\n        CronExpression copyCronExpression = new CronExpression(cronExpression);\n        assertEquals(nonDefault, copyCronExpression.getTimeZone());\n    }\n\n    // Issue #58\n    @Test\n    void testSecRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"/120 0 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0/120 0 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"/ 0 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0/ 0 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 5\n        try {\n            new CronExpression(\"/60 0 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 60\", e.getMessage());\n        }\n    }\n\n\n    // Issue #58\n    @Test\n    void testMinRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"0 /120 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0 0/120 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"0 / 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0 0/ 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 5\n        try {\n            new CronExpression(\"0 /60 8-18 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 60 : 60\", e.getMessage());\n        }\n    }\n\n    // Issue #58\n    @Test\n    void testHourRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"0 0 /120 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 24 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0 0 0/120 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 24 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"0 0 / ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0 0 0/ ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 5\n        try {\n            new CronExpression(\"0 0 /24 ? * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 24 : 24\", e.getMessage());\n        }\n    }\n\n    // Issue #58\n    @Test\n    void testDayOfMonthRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"0 0 0 /120 * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 31 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0 0 0 0/120 * 2-6\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 31 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"0 0 0 / * 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0 0 0 0/ * 2-6\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n    }\n\n    // Issue #58\n    @Test\n    void testMonthRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"0 0 0 ? /120 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 12 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0 0 0 ? 0/120 2-6\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 12 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"0 0 0 ? / 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0 0 0 ? 0/ 2-6\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 5\n        try {\n            new CronExpression(\"0 0 0 ? /13 2-6\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 12 : 13\", e.getMessage());\n        }\n    }\n\n\n\n    // Issue #58\n    @Test\n    void testDayOfWeekRangeIntervalAfterSlash() throws Exception {\n        // Test case 1\n        try {\n            new CronExpression(\"0 0 0 ? * /120\");\n            fail(\"Cron did not validate bad range interval in '_blank/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 7 : 120\", e.getMessage());\n        }\n\n        // Test case 2\n        try {\n            new CronExpression(\"0 0 0 ? * 0/120\");\n            fail(\"Cron did not validate bad range interval in in '0/xxx' form\");\n        } catch (ParseException e) {\n            assertEquals(\"Increment >= 7 : 120\", e.getMessage());\n        }\n\n        // Test case 3\n        try {\n            new CronExpression(\"0 0 0 ? * /\");\n            fail(\"Cron did not validate bad range interval in '_blank/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n\n        // Test case 4\n        try {\n            new CronExpression(\"0 0 0 ? * 0/\");\n            fail(\"Cron did not validate bad range interval in '0/_blank'\");\n        } catch (ParseException e) {\n            assertEquals(\"'/' must be followed by an integer.\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testGetTimeBefore() throws ParseException {\n        long now = System.currentTimeMillis();\n        Calendar cal = Calendar.getInstance();\n        cal.setTimeInMillis(now);\n        int year = cal.get(Calendar.YEAR);\n\n        Object[][] tests = {\n            { \"* * * * * ? *\", 1000L },\n            { \"0 * * * * ? *\", 60 * 1000L },\n            { \"0/15 * * * * ? *\", 15 * 1000L },\n            { \"0 0 5 * * ? *\", 24 * 60 * 60 * 1000L },\n            { \"0 0 0 * * ? *\", 24 * 60 * 60 * 1000L },\n            { \"0/30 1 2 * * ? *\", 24 * 60 * 60 * 1000L - 30000L, 30000L },\n            { \"* * * * * ? \" + (year + 2) },\n            { \"* * * * * ? \" + (year - 2), 24 * 60 * 60 * 1000L - 30000L, 30000L },\n        };\n        for (Object[] test : tests) {\n            String expression = (String)test[0];\n            long interval1 = test.length > 1 ? (long)test[1] : -1;\n            long interval2 = test.length > 2 ? (long)test[2] : interval1;\n            CronExpression exp = new CronExpression(expression);\n            Date after = exp.getTimeAfter(new Date(now));\n            if (after == null) { // matches only in the past\n                Date before = exp.getTimeBefore(new Date(now));\n                assertNotNull(before, \"expression \" + expression);\n            } else if (interval1 < 0) { // matches only in the future\n                Date before = exp.getTimeBefore(after);\n                assertNull(before, \"expression \" + expression);\n            } else { // matches at fixed intervals\n                Date before = exp.getTimeBefore(after);\n                Date after2 = exp.getTimeAfter(after);\n                assertEquals(interval1, after.getTime() - before.getTime(), \"expression \" + expression);\n                assertEquals(interval2, after2.getTime() - after.getTime(), \"expression \" + expression);\n            }\n        }\n    }\n\n    @Test\n    public void testIsValidExpression() throws Exception {\n\n        assertTrue(CronExpression.isValidExpression(\"* * * * * ?\"));\n        assertTrue(CronExpression.isValidExpression(\"0 * 5 * * ?\"));\n        assertTrue(CronExpression.isValidExpression(\"0 15 10 L-1W,L-1 * ? 2010\"));\n        assertFalse(CronExpression.isValidExpression(\"Ralf 30 * * * ?\"));\n        assertFalse(CronExpression.isValidExpression(\"0 30 Ralf * * ?\"));\n        assertFalse(CronExpression.isValidExpression(\"kilroy was here\"));\n        assertFalse(CronExpression.isValidExpression(\"L 30 * * * ?\"));\n    }\n\n    @Test\n    public void test1420() throws Exception {\n\n        // seconds minute hours day-of-month month day-of-week year\n\n        CronExpression expFirstWeekdayOfTheMonth = new CronExpression(\"0 0 0 1W * ?\");\n        CronExpression expLastDayOfMonth = new CronExpression(\"59 59 23 L * ?\");\n\n        assertTrue(CronExpression.isValidExpression(expFirstWeekdayOfTheMonth.getCronExpression()));\n        assertTrue(CronExpression.isValidExpression(expLastDayOfMonth.getCronExpression()));\n\n        List<Date> correctFireTimes = new ArrayList<>();\n\n        Calendar cal = Calendar.getInstance();\n        cal.set(Calendar.MILLISECOND, 0);\n        cal.set(2025, Calendar.DECEMBER, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JANUARY, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.FEBRUARY, 2, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.MARCH, 2, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.APRIL, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.MAY, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JUNE, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JULY, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.AUGUST, 3, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.SEPTEMBER, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.OCTOBER, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.NOVEMBER, 2, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.DECEMBER, 1, 0, 0, 0);\n        correctFireTimes.add(cal.getTime());\n\n        cal.set(2025, Calendar.NOVEMBER, 18, 10, 15, 0);\n        Date lTime = cal.getTime();\n\n        // test correct computed dates for first weekdays days of month\n        for(int i=0; i < 13; i++) {\n            Date nTime = expFirstWeekdayOfTheMonth.getTimeAfter(lTime);\n            assertEquals(correctFireTimes.get(i), nTime);\n            lTime = nTime;\n        }\n\n        correctFireTimes.clear();\n\n        cal.set(2025, Calendar.NOVEMBER, 30, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2025, Calendar.DECEMBER, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JANUARY, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.FEBRUARY, 28, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.MARCH, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.APRIL, 30, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.MAY, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JUNE, 30, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.JULY, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.AUGUST, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.SEPTEMBER, 30, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.OCTOBER, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.NOVEMBER, 30, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n        cal.set(2026, Calendar.DECEMBER, 31, 23, 59, 59);\n        correctFireTimes.add(cal.getTime());\n\n        cal.set(2025, Calendar.NOVEMBER, 18, 10, 15, 0);\n        lTime = cal.getTime();\n\n        // test correct computed dates for last days of month\n        for(int i=0; i < 14; i++) {\n            Date nTime = expLastDayOfMonth.getTimeAfter(lTime);\n            assertEquals(correctFireTimes.get(i), nTime);\n            lTime = nTime;\n        }\n    }\n\n    // execute with version number to generate a new version's serialized form\n    public static void main(String[] args) throws Exception {\n        new CronExpressionTest().writeJobDataFile(\"1.5.2\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/CronScheduleBuilderTest.java",
    "content": "/* \r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n * \r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \r\n * use this file except in compliance with the License. You may obtain a copy \r\n * of the License at \r\n * \r\n *   http://www.apache.org/licenses/LICENSE-2.0 \r\n *   \r\n * Unless required by applicable law or agreed to in writing, software \r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \r\n * License for the specific language governing permissions and limitations \r\n * under the License.\r\n * \r\n */\r\npackage org.quartz;\r\n\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.quartz.CronScheduleBuilder.atHourAndMinuteOnGivenDaysOfWeek;\r\nimport static org.quartz.TriggerBuilder.newTrigger;\r\n\r\n\r\n\r\n/**\r\n * Unit test for CronScheduleBuilder.\r\n * \r\n * @author jhouse\r\n *\r\n */\r\npublic class CronScheduleBuilderTest  {\r\n\r\n\t@Test\r\n\tvoid testAtHourAndMinuteOnGivenDaysOfWeek() {\r\n\t\t\r\n\t\tCronTrigger trigger = newTrigger().withIdentity(\"test\")\r\n\t\t\t\t.withSchedule(\r\n\t\t\t\t\tatHourAndMinuteOnGivenDaysOfWeek(10, 0, DateBuilder.MONDAY, DateBuilder.THURSDAY, DateBuilder.FRIDAY))\r\n\t\t\t\t.build();\r\n\t\tassertEquals(\"0 0 10 ? * 2,5,6\", trigger.getCronExpression());\r\n\r\n\t\ttrigger = newTrigger().withIdentity(\"test\")\r\n\t\t\t.withSchedule(\r\n\t\t\tatHourAndMinuteOnGivenDaysOfWeek(10, 0, DateBuilder.WEDNESDAY))\r\n\t\t\t.build();\r\n\t\tassertEquals(\"0 0 10 ? * 4\", trigger.getCronExpression());\r\n\t}\r\n\t\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/CronTriggerTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.text.ParseException;\n\nimport org.quartz.impl.triggers.CronTriggerImpl;\n\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.*;\n\n/**\n * Unit test for CronTrigger.\n */\npublic class CronTriggerTest extends SerializationTestSupport {\n\n    private static final String[] VERSIONS = new String[] {\"2.0\"};\n\n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @Override\n    protected Object getTargetObject() throws Exception {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"A\", \"B\");\n        \n        CronTriggerImpl t = new CronTriggerImpl();\n        t.setName(\"test\");\n        t.setGroup(\"testGroup\");\n        t.setCronExpression(\"0 0 12 * * ?\");\n        t.setCalendarName(\"MyCalendar\");\n        t.setDescription(\"CronTriggerDesc\");\n        t.setJobDataMap(jobDataMap);\n\n        return t;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        CronTriggerImpl targetCronTrigger = (CronTriggerImpl)target;\n        CronTriggerImpl deserializedCronTrigger = (CronTriggerImpl)deserialized;\n\n        assertNotNull(deserializedCronTrigger);\n        assertEquals(targetCronTrigger.getName(), deserializedCronTrigger.getName());\n        assertEquals(targetCronTrigger.getGroup(), deserializedCronTrigger.getGroup());\n        assertEquals(targetCronTrigger.getJobName(), deserializedCronTrigger.getJobName());\n        assertEquals(targetCronTrigger.getJobGroup(), deserializedCronTrigger.getJobGroup());\n//        assertEquals(targetCronTrigger.getStartTime(), deserializedCronTrigger.getStartTime());\n        assertEquals(targetCronTrigger.getEndTime(), deserializedCronTrigger.getEndTime());\n        assertEquals(targetCronTrigger.getCalendarName(), deserializedCronTrigger.getCalendarName());\n        assertEquals(targetCronTrigger.getDescription(), deserializedCronTrigger.getDescription());\n        assertEquals(targetCronTrigger.getJobDataMap(), deserializedCronTrigger.getJobDataMap());\n        assertEquals(targetCronTrigger.getCronExpression(), deserializedCronTrigger.getCronExpression());\n    }\n        \n    \n    void testClone() throws ParseException {\n        CronTriggerImpl trigger = new CronTriggerImpl();\n        trigger.setName(\"test\");\n        trigger.setGroup(\"testGroup\");\n        trigger.setCronExpression(\"0 0 12 * * ?\");\n        CronTrigger trigger2 = (CronTrigger) trigger.clone();\n\n        assertEquals(trigger, trigger2, \"Cloning failed\");\n\n        // equals() doesn't test the cron expression\n        assertEquals( \"Cloning failed for the cron expression\", \n                      \"0 0 12 * * ?\", trigger2.getCronExpression()\n                    );\n    }\n\n    // http://jira.opensymphony.com/browse/QUARTZ-558\n    void testQuartz558() throws ParseException {\n        CronTriggerImpl trigger = new CronTriggerImpl();\n        trigger.setName(\"test\");\n        trigger.setGroup(\"testGroup\");\n        CronTrigger trigger2 = (CronTrigger) trigger.clone();\n\n        assertEquals(trigger, trigger2, \"Cloning failed\");\n    }\n\n    void testMisfireInstructionValidity() throws ParseException {\n        CronTriggerImpl trigger = new CronTriggerImpl();\n\n        try {\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_SMART_POLICY);\n            trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);\n            trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);\n        }\n        catch(Exception e) {\n            fail(\"Unexpected exception while setting misfire instruction.\");\n        }\n        \n        try {\n            trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING + 1);\n            \n            fail(\"Expected exception while setting invalid misfire instruction but did not get it.\");\n        }\n        catch(Exception e) {\n        }\n    }\n\n    void testMisfireInstructionInDerivedBuilder() throws ParseException {\n        for (int policy : asList(\n                Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY,\n                Trigger.MISFIRE_INSTRUCTION_SMART_POLICY,\n                CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING,\n                CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW)\n        ) {\n            CronTriggerImpl trigger = new CronTriggerImpl();\n            trigger.setCronExpression(\"0 0 12 * * ?\");\n            trigger.setMisfireInstruction(policy);\n            assertThat(trigger.getMisfireInstruction(), is(policy));\n\n            CronTrigger copy = trigger.getTriggerBuilder().build();\n            assertThat(copy.getMisfireInstruction(), is(policy));\n        }\n    }\n\n    void testUndefinedMisfireInstructionInDerivedBuilder() throws ParseException {\n        CronTriggerImpl trigger = new CronTriggerImpl() {\n            @Override\n            public int getMisfireInstruction() {\n                return 12345;\n            }\n        };\n        trigger.setCronExpression(\"0 0 12 * * ?\");\n        try {\n            trigger.setMisfireInstruction(12345);\n            fail(\"Expected IllegalArgumentException\");\n        } catch (IllegalArgumentException e) {\n            assertThat(e.getMessage(), is(\"The misfire instruction code is invalid for this type of trigger.\"));\n        }\n\n        CronTrigger copy = trigger.getTriggerBuilder().build();\n        assertThat(copy.getMisfireInstruction(), is(Trigger.MISFIRE_INSTRUCTION_SMART_POLICY));\n    }\n\n    // execute with version number to generate a new version's serialized form\n    public static void main(String[] args) throws Exception {\n        new CronTriggerTest().writeJobDataFile(\"2.0\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/DailyTimeIntervalScheduleBuilderTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.quartz.DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule;\nimport static org.quartz.DateBuilder.dateOf;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TimeOfDay.hourMinuteAndSecondOfDay;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.util.Date;\nimport java.util.List;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.spi.OperableTrigger;\n\n/**\n * Unit test for DailyTimeIntervalScheduleBuilder.\n * \n * @author Zemian Deng <saltnlight5@gmail.com>\n *\n */\npublic class DailyTimeIntervalScheduleBuilderTest  {\n\n  @Test\n  void testScheduleActualTrigger() throws Exception {\n    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();\n    JobDetail job = newJob(MyJob.class).build();\n    DailyTimeIntervalTrigger trigger = newTrigger().withIdentity(\"test\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .withIntervalInSeconds(3))\n            .build();\n    scheduler.scheduleJob(job, trigger); //We are not verify anything other than just run through the scheduler.\n    scheduler.shutdown();\n  }\n  \n  void testScheduleInMiddleOfDailyInterval() throws Exception {\n    \n    java.util.Calendar currTime = java.util.Calendar.getInstance();\n    \n    int currHour = currTime.get(java.util.Calendar.HOUR);\n    \n    // this test won't work out well in the early hours, where 'backing up' would give previous day,\n    // or where daylight savings transitions could occur and confuse the assertions...\n    if(currHour < 3)\n      return;\n    \n    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();\n    JobDetail job = newJob(MyJob.class).build();\n    Trigger trigger = newTrigger().withIdentity(\"test\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(2, 15))\n            .withIntervalInMinutes(5))\n            .startAt(currTime.getTime())\n            .build();\n    scheduler.scheduleJob(job, trigger); \n    \n    trigger = scheduler.getTrigger(trigger.getKey());\n    \n    System.out.println(\"testScheduleInMiddleOfDailyInterval: currTime = \" + currTime.getTime());\n    System.out.println(\"testScheduleInMiddleOfDailyInterval: computed first fire time = \" + trigger.getNextFireTime());\n        \n    assertTrue(trigger.getNextFireTime().after(currTime.getTime()), \"First fire time is not after now!\");\n    \n    \n    Date startTime = DateBuilder.todayAt(2, 15, 0);\n    \n    job = newJob(MyJob.class).build();\n    trigger = newTrigger().withIdentity(\"test2\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(2, 15))\n            .withIntervalInMinutes(5))\n            .startAt(startTime)\n            .build();\n    scheduler.scheduleJob(job, trigger); \n    \n    trigger = scheduler.getTrigger(trigger.getKey());\n    \n    System.out.println(\"testScheduleInMiddleOfDailyInterval: startTime = \" + startTime);\n    System.out.println(\"testScheduleInMiddleOfDailyInterval: computed first fire time = \" + trigger.getNextFireTime());\n\n      assertEquals(trigger.getNextFireTime(), startTime, \"First fire time is not after now!\");\n \n    \n    scheduler.shutdown();\n  }\n\n  @Test\n  void testHourlyTrigger() {\n    DailyTimeIntervalTrigger trigger = newTrigger().withIdentity(\"test\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .withIntervalInHours(1))\n            .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"DEFAULT\", trigger.getKey().getGroup());\n    assertEquals(IntervalUnit.HOUR, trigger.getRepeatIntervalUnit());\n    assertEquals(1, trigger.getRepeatInterval());\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(48, fireTimes.size());\n  }\n\n  @Test\n  void testMinutelyTriggerWithTimeOfDay() {\n    DailyTimeIntervalTrigger trigger = newTrigger().withIdentity(\"test\", \"group\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .withIntervalInMinutes(72)\n            .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0))\n            .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0))\n            .onMondayThroughFriday())\n            .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"group\", trigger.getKey().getGroup());\n      assertTrue(new Date().getTime() >= trigger.getStartTime().getTime());\n      assertNull(trigger.getEndTime());\n    assertEquals(IntervalUnit.MINUTE, trigger.getRepeatIntervalUnit());\n    assertEquals(72, trigger.getRepeatInterval());\n    assertEquals(new TimeOfDay(8, 0), trigger.getStartTimeOfDay());\n    assertEquals(new TimeOfDay(17, 0), trigger.getEndTimeOfDay());\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(48, fireTimes.size());\n  }\n\n  @Test\n  void testSecondlyTriggerWithStartAndEndTime() {\n    Date startTime = DateBuilder.dateOf(0,  0, 0, 1, 1, 2011);\n    Date endTime = DateBuilder.dateOf(0, 0, 0, 2, 1, 2011);\n    DailyTimeIntervalTrigger trigger = newTrigger().withIdentity(\"test\", \"test\")\n        .withSchedule(dailyTimeIntervalSchedule()\n            .withIntervalInSeconds(121)\n            .startingDailyAt(hourMinuteAndSecondOfDay(10, 0, 0))\n            .endingDailyAt(hourMinuteAndSecondOfDay(23, 59, 59))\n            .onSaturdayAndSunday())\n            .startAt(startTime)\n            .endAt(endTime)\n            .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"test\", trigger.getKey().getGroup());\n      assertEquals(startTime.getTime(), trigger.getStartTime().getTime());\n      assertEquals(endTime.getTime(), trigger.getEndTime().getTime());\n    assertEquals(IntervalUnit.SECOND, trigger.getRepeatIntervalUnit());\n    assertEquals(121, trigger.getRepeatInterval());\n    assertEquals(new TimeOfDay(10, 0, 0), trigger.getStartTimeOfDay());\n    assertEquals(new TimeOfDay(23, 59, 59), trigger.getEndTimeOfDay());\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(48, fireTimes.size());\n  }\n\n  @Test\n  void testRepeatCountTrigger() {\n    DailyTimeIntervalTrigger trigger = newTrigger()\n        .withIdentity(\"test\")\n        .withSchedule(\n            dailyTimeIntervalSchedule()\n            .withIntervalInHours(1)\n            .withRepeatCount(9))\n        .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"DEFAULT\", trigger.getKey().getGroup());\n    assertEquals(IntervalUnit.HOUR, trigger.getRepeatIntervalUnit());\n    assertEquals(1, trigger.getRepeatInterval());\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(10, fireTimes.size());\n  }\n\n  @Test\n  void testEndingAtAfterCount() {\n    Date startTime = DateBuilder.dateOf(0,  0, 0, 1, 1, 2011);\n    DailyTimeIntervalTrigger trigger = newTrigger()\n        .withIdentity(\"test\")\n        .withSchedule(\n            dailyTimeIntervalSchedule()\n            .withIntervalInMinutes(15)\n            .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0))\n            .endingDailyAfterCount(12))\n        .startAt(startTime)\n        .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"DEFAULT\", trigger.getKey().getGroup());\n    assertEquals(IntervalUnit.MINUTE, trigger.getRepeatIntervalUnit());\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(48, fireTimes.size());\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\n    assertEquals(dateOf(10, 45, 0, 4, 1, 2011), fireTimes.get(47));\n    assertEquals(new TimeOfDay(10, 45), trigger.getEndTimeOfDay());\n  }\n\n  @Test\n  void testEndingAtAfterCountOf1() {\n    Date startTime = DateBuilder.dateOf(0,  0, 0, 1, 1, 2011);\n    DailyTimeIntervalTrigger trigger = newTrigger()\n        .withIdentity(\"test\")\n        .withSchedule(\n            dailyTimeIntervalSchedule()\n            .withIntervalInMinutes(15)\n            .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0))\n            .endingDailyAfterCount(1))\n        .startAt(startTime)\n        .forJob(\"testJob\", \"testJobGroup\")\n        .build();\n    assertEquals(\"test\", trigger.getKey().getName());\n    assertEquals(\"DEFAULT\", trigger.getKey().getGroup());\n    assertEquals(IntervalUnit.MINUTE, trigger.getRepeatIntervalUnit());\n    validateTrigger(trigger);\n    List<Date> fireTimes = TriggerUtils.computeFireTimes((OperableTrigger)trigger, null, 48);\n    assertEquals(48, fireTimes.size());\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\n    assertEquals(dateOf(8, 0, 0, 17, 2, 2011), fireTimes.get(47));\n    assertEquals(new TimeOfDay(8, 0), trigger.getEndTimeOfDay());\n  }\n\n  private void validateTrigger(DailyTimeIntervalTrigger trigger) {\n    try {\n      ((OperableTrigger) trigger).validate();\n    } catch (SchedulerException e) {\n      throw new RuntimeException(\"Trigger \" + trigger.getKey() + \" failed to validate\", e);\n    }\n  }\n\n  @Test\n  void testEndingAtAfterCountOf0() {\n    try {\n      Date startTime = DateBuilder.dateOf(0,  0, 0, 1, 1, 2011);\n      newTrigger()\n          .withIdentity(\"test\")\n          .withSchedule(\n              dailyTimeIntervalSchedule()\n              .withIntervalInMinutes(15)\n              .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0))\n              .endingDailyAfterCount(0))\n          .startAt(startTime)\n          .build();\n      fail(\"We should not accept endingDailyAfterCount(0)\");\n    } catch (IllegalArgumentException e) {\n      // Expected.\n    }\n    \n    try {\n      Date startTime = DateBuilder.dateOf(0,  0, 0, 1, 1, 2011);\n      newTrigger()\n          .withIdentity(\"test\")\n          .withSchedule(\n              dailyTimeIntervalSchedule()\n              .withIntervalInMinutes(15)\n              .endingDailyAfterCount(1))\n          .startAt(startTime)\n          .build();\n      fail(\"We should not accept endingDailyAfterCount(x) without first setting startingDailyAt.\");\n    } catch (IllegalArgumentException e) {\n      // Expected.\n    }\n  }\n  \n    /** An empty job for testing purpose. */\n    public static class MyJob implements Job {\n      public void execute(JobExecutionContext context) throws JobExecutionException {\n        //\n      }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/DateBuilderTest.java",
    "content": "package org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.assertAll;\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.quartz.DateBuilder.JULY;\nimport static org.quartz.DateBuilder.JUNE;\nimport static org.quartz.DateBuilder.dateOf;\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.DateBuilder.newDate;\nimport static org.quartz.DateBuilder.newDateInLocale;\nimport static org.quartz.DateBuilder.newDateInTimeZoneAndLocale;\nimport static org.quartz.DateBuilder.newDateInTimezone;\nimport static org.quartz.DateBuilder.todayAt;\nimport static org.quartz.DateBuilder.translateTime;\n\nimport java.time.Clock;\nimport java.time.DateTimeException;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.time.ZoneOffset;\nimport java.time.ZonedDateTime;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.TimeZone;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.quartz.DateBuilder.IntervalUnit;\n\nclass DateBuilderTest {\n\n    @Test\n    void testJustInstantiatedBuilderShouldReturnSameInstantTruncatedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T10:15:30.999Z\"), ZoneOffset.UTC);\n        var builder = DateBuilder.newDate();\n        builder.setClock(clock);\n\n        assertEquals(Date.from(Instant.parse(\"2007-12-03T10:15:30.000Z\")), builder.build());\n    }\n\n    @Test\n    void testBuilder() {\n        var expected = ZonedDateTime.of(2013, 07, 1, 10, 30, 0, 0, ZoneId.systemDefault()).toInstant();\n\n        var bd1 = newDate().inYear(2013).inMonth(JULY).onDay(1).atHourOfDay(10).atMinute(30).atSecond(0).build();\n        var bd2 = newDate().inYear(2013).inMonthOnDay(JULY, 1).atHourMinuteAndSecond(10, 30, 0).build();\n\n        assertAll(\n                \"dateBuilderDefaultTimeZone\",\n                () -> assertEquals(expected, bd1.toInstant()),\n                () -> assertEquals(expected, bd2.toInstant()));\n    }\n\n    @Test\n    void testBuilderWithTimeZone() {\n        TimeZone tz = TimeZone.getTimeZone(\"GMT-4:00\");\n        var expected = Instant.parse(\"2013-06-01T14:33:12.000Z\");\n\n        Locale lz = Locale.TAIWAN;\n\n        var bd1 = newDate().inYear(2013)\n                .inMonth(JUNE)\n                .onDay(1)\n                .atHourOfDay(10)\n                .atMinute(33)\n                .atSecond(12)\n                .inTimeZone(tz)\n                .inLocale(lz)\n                .build();\n\n        var bd2 = newDateInLocale(lz).inYear(2013)\n                .inMonth(JUNE)\n                .onDay(1)\n                .atHourOfDay(10)\n                .atMinute(33)\n                .atSecond(12)\n                .inTimeZone(tz)\n                .build();\n\n        var bd3 = newDateInTimezone(tz).inYear(2013)\n                .inMonth(JUNE)\n                .onDay(1)\n                .atHourOfDay(10)\n                .atMinute(33)\n                .atSecond(12)\n                .inLocale(lz)\n                .build();\n\n        var bd4 = newDateInTimeZoneAndLocale(tz, lz).inYear(2013)\n                .inMonth(JUNE)\n                .onDay(1)\n                .atHourOfDay(10)\n                .atMinute(33)\n                .atSecond(12)\n                .build();\n\n        assertAll(\n                \"dateBuilderWithCustomTimeZone\",\n                () -> assertEquals(expected, bd1.toInstant()),\n                () -> assertEquals(expected, bd2.toInstant()),\n                () -> assertEquals(expected, bd3.toInstant()),\n                () -> assertEquals(expected, bd4.toInstant()));\n    }\n\n    /*\n     * futureDate tests\n     */\n\n    private static Stream<Arguments> futureDateTestData() {\n        return Stream.of(\n                Arguments.of(1, IntervalUnit.MILLISECOND, \"2007-12-03T10:15:30.001Z\"),\n                Arguments.of(1, IntervalUnit.SECOND, \"2007-12-03T10:15:31.000Z\"),\n                Arguments.of(1, IntervalUnit.MINUTE, \"2007-12-03T10:16:30.000Z\"),\n                Arguments.of(1, IntervalUnit.HOUR, \"2007-12-03T11:15:30.000Z\"),\n                Arguments.of(1, IntervalUnit.DAY, \"2007-12-04T10:15:30.000Z\"),\n                Arguments.of(1, IntervalUnit.WEEK, \"2007-12-10T10:15:30.000Z\"),\n                Arguments.of(1, IntervalUnit.MONTH, \"2008-01-03T10:15:30.000Z\"),\n                Arguments.of(1, IntervalUnit.YEAR, \"2008-12-03T10:15:30.000Z\"));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"futureDateTestData\")\n    void testFutureDate(int interval, IntervalUnit unit, String expected) {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T10:15:30.000Z\"), ZoneId.systemDefault());\n\n        assertEquals(Date.from(Instant.parse(expected)), futureDate(interval, unit, clock));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"futureDateTestData\")\n    void testFutureDateWithNonDefaultZone(int interval, IntervalUnit unit, String expected) {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T10:15:30.000Z\"), ZoneOffset.ofHoursMinutes(3, 15));\n\n        assertEquals(Date.from(Instant.parse(expected)), futureDate(interval, unit, clock));\n    }\n\n    /*\n     * tomorrowAt tests\n     */\n\n    private static Stream<Arguments> tomorrowAtTestData() {\n        return Stream.of(\n                Arguments.of(\"2024-10-25T23:59:30.999Z\", ZoneOffset.UTC, \"2024-10-26T02:30:20.000Z\"),\n                Arguments.of(\n                        \"2024-03-30T23:59:59.999+01:00\",\n                        ZoneId.of(\"Europe/Vienna\"),\n                        \"2024-03-31T03:30:20.000+02:00\"), // DST change skipped one hour\n                Arguments.of(\n                        \"2024-10-26T23:59:59.999+01:00\",\n                        ZoneId.of(\"Europe/Vienna\"),\n                        \"2024-10-27T02:30:20.000+01:00\")); // DST change added one hour\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"tomorrowAtTestData\")\n    void testTomorrowAt(String input, ZoneId zoneId, String expected) {\n        var instant = ZonedDateTime.parse(input).toInstant();\n        var clock = Clock.fixed(instant, zoneId);\n        var tomorrow = DateBuilder.tomorrowAt(2, 30, 20, clock);\n\n        assertEquals(Date.from(ZonedDateTime.parse(expected).toInstant()), tomorrow);\n    }\n\n    /*\n     * todayAt tests\n     */\n\n    @ParameterizedTest\n    @MethodSource(\"testDateOf3PWithInvalidParametersTestData\")\n    void testTodayAtInvalidValues(int hour, int minute, int second) {\n        assertThrows(DateTimeException.class, () -> todayAt(hour, minute, second));\n    }\n\n    @Test\n    void testTodayAt() {\n        var clock1 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        var date1 = DateBuilder.todayAt(1, 1, 1, clock1);\n        var clock2 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneId.of(\"Europe/Vienna\"));\n        var date2 = DateBuilder.todayAt(1, 1, 1, clock2);\n        var clock3 = Clock.fixed(Instant.parse(\"2024-03-31T08:13:54.341Z\"), ZoneId.of(\"Europe/Vienna\"));\n        var dstSkippedHour = DateBuilder.todayAt(2, 30, 17, clock3); // DST change => skipped hour\n\n        assertAll(\n                \"dateOf3P\",\n                () -> assertNotEquals(date1, date2),\n                () -> assertEquals(Instant.parse(\"2007-12-03T01:01:01.000Z\"), date1.toInstant()),\n                () -> assertEquals(Instant.parse(\"2007-12-03T00:01:01.000Z\"), date2.toInstant()),\n                () -> assertEquals(\n                        ZonedDateTime.parse(\"2024-03-31T03:30:17.000+02:00\")\n                                .toInstant(),\n                        dstSkippedHour.toInstant()));\n    }\n\n    /*\n     * dateOf tests\n     */\n\n    private static Stream<Arguments> testDateOf3PWithInvalidParametersTestData() {\n        return Stream.of(\n                Arguments.of(-1, 0, 0),\n                Arguments.of(24, 0, 0),\n                Arguments.of(0, -1, 0),\n                Arguments.of(0, 60, 0),\n                Arguments.of(0, 0, -1),\n                Arguments.of(0, 0, 60));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"testDateOf3PWithInvalidParametersTestData\")\n    void testDateOf3PWithInvalidParameters(int hour, int minute, int second) {\n        assertThrows(DateTimeException.class, () -> dateOf(hour, minute, second));\n    }\n\n    @Test\n    void testDateOf3P() {\n        var clock1 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        var clock2 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneId.of(\"Europe/Vienna\"));\n        var date1 = DateBuilder.dateOf(1, 1, 1, clock1);\n        var date2 = DateBuilder.dateOf(1, 1, 1, clock2);\n        assertAll(\n                \"dateOf3P\",\n                () -> assertNotEquals(date1, date2),\n                () -> assertEquals(Instant.parse(\"2007-12-03T01:01:01.000Z\"), date1.toInstant()),\n                () -> assertEquals(Instant.parse(\"2007-12-03T00:01:01.000Z\"), date2.toInstant()));\n    }\n\n    private static Stream<Arguments> testDateOf5PWithInvalidParametersTestData() {\n        return Stream.of(\n                Arguments.of(-1, 0, 0, 0, 0),\n                Arguments.of(24, 0, 0, 0, 0),\n                Arguments.of(0, -1, 0, 0, 0),\n                Arguments.of(0, 60, 0, 0, 0),\n                Arguments.of(0, 0, -1, 0, 0),\n                Arguments.of(0, 0, 60, 0, 0),\n                Arguments.of(0, 0, 0, 0, 0),\n                Arguments.of(0, 0, 0, 32, 0),\n                Arguments.of(0, 0, 0, 0, 0),\n                Arguments.of(0, 0, 0, 0, 13),\n                Arguments.of(0, 0, 0, 0, 0),\n                Arguments.of(0, 0, 0, 0, 0));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"testDateOf5PWithInvalidParametersTestData\")\n    void testDateOf5PWithInvalidParameters(int hour, int minute, int second,\n            int dayOfMonth, int month) {\n        assertThrows(DateTimeException.class, () -> dateOf(hour, minute, second, dayOfMonth, month));\n    }\n\n    @Test\n    void testDateOf5P() {\n        var clock1 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        var clock2 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneId.of(\"Europe/Vienna\"));\n        var date1 = DateBuilder.dateOf(1, 1, 1, 1, 1, clock1);\n        var date2 = DateBuilder.dateOf(1, 1, 1, 1, 1, clock2);\n        assertAll(\n                \"dateOf6P\",\n                () -> assertNotEquals(date1, date2),\n                () -> assertEquals(Instant.parse(\"2007-01-01T01:01:01.000Z\"), date1.toInstant()),\n                () -> assertEquals(Instant.parse(\"2007-01-01T00:01:01.000Z\"), date2.toInstant()));\n    }\n\n    private static Stream<Arguments> testDateOf6PWithInvalidParametersTestData() {\n        return Stream.of(\n                Arguments.of(-1, 0, 0, 0, 0, 0),\n                Arguments.of(24, 0, 0, 0, 0, 0),\n                Arguments.of(0, -1, 0, 0, 0, 0),\n                Arguments.of(0, 60, 0, 0, 0, 0),\n                Arguments.of(0, 0, -1, 0, 0, 0),\n                Arguments.of(0, 0, 60, 0, 0, 0),\n                Arguments.of(0, 0, 0, 0, 0, 0),\n                Arguments.of(0, 0, 0, 32, 0, 0),\n                Arguments.of(0, 0, 0, 0, 0, 0),\n                Arguments.of(0, 0, 0, 0, 13, 0),\n                Arguments.of(0, 0, 0, 0, 0, -1_000_000_000),\n                Arguments.of(0, 0, 0, 0, 0, 1_000_000_000));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"testDateOf6PWithInvalidParametersTestData\")\n    void testDateOf6PWithInvalidParameters(int hour, int minute, int second,\n            int dayOfMonth, int month, int year) {\n        assertThrows(DateTimeException.class, () -> dateOf(hour, minute, second, dayOfMonth, month, year));\n    }\n\n    @Test\n    void testDateOf6P() {\n        var clock1 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        var clock2 = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneId.of(\"Europe/Vienna\"));\n        var date1 = DateBuilder.dateOf(1, 1, 1, 1, 1, 2024, clock1);\n        var date2 = DateBuilder.dateOf(1, 1, 1, 1, 1, 2024, clock2);\n        assertAll(\n                \"dateOf6P\",\n                () -> assertNotEquals(date1, date2),\n                () -> assertEquals(Instant.parse(\"2024-01-01T01:01:01.000Z\"), date1.toInstant()),\n                () -> assertEquals(Instant.parse(\"2024-01-01T00:01:01.000Z\"), date2.toInstant()));\n    }\n\n    /*\n     * evenHourDateAfterNow tests\n     */\n\n    @Test\n    void testEvenHourDateAfterNow() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T09:00:00.000Z\"),\n                DateBuilder.evenHourDateAfterNow(clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenHourDate tests\n     */\n\n    @Test\n    void testEvenHourDate() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T09:00:00.000Z\"),\n                DateBuilder.evenHourDate(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenHourDateWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T09:00:00.000Z\"),\n                DateBuilder.evenHourDate(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenHourDateBefore tests\n     */\n\n    @Test\n    void testEvenHourDateBefore() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:00:00.000Z\"),\n                DateBuilder.evenHourDateBefore(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenHourDateBeforeWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:00:00.000Z\"),\n                DateBuilder.evenHourDateBefore(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenMinuteDateAfterNow tests\n     */\n\n    @Test\n    void testEvenMinuteDateAfterNow() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:14:00.000Z\"),\n                DateBuilder.evenMinuteDateAfterNow(clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenMinuteDate tests\n     */\n\n    @Test\n    void testEvenMinuteDate() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:14:00.000Z\"),\n                DateBuilder.evenMinuteDate(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenMinuteDateWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:14:00.000Z\"),\n                DateBuilder.evenMinuteDate(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenMinuteDateBefore tests\n     */\n\n    @Test\n    void testEvenMinuteDateBefore() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:00.000Z\"),\n                DateBuilder.evenMinuteDateBefore(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenMinuteDateBeforeWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:00.000Z\"),\n                DateBuilder.evenMinuteDateBefore(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenSecondDateAfterNow tests\n     */\n\n    @Test\n    void testEvenSecondDateAfterNow() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:55.000Z\"),\n                DateBuilder.evenSecondDateAfterNow(clock)\n                        .toInstant());\n    }\n\n    @Test\n    void testEvenSecondDateAfterNowDSTForward() {\n        var clock = Clock.fixed(\n                ZonedDateTime.parse(\"2024-03-31T01:59:59.999+01:00\")\n                        .toInstant(),\n                ZoneId.of(\"Europe/Vienna\"));\n        var before = clock.instant();\n        var result = DateBuilder.evenSecondDateAfterNow(clock).toInstant();\n\n        assertAll(\"DSTChange+1H\",\n                () -> assertEquals(ZonedDateTime.parse(\"2024-03-31T01:59:59.999+01:00\").toInstant(), before),\n                () -> assertEquals(ZonedDateTime.parse(\"2024-03-31T01:00:00.000Z\").toInstant(), result),\n                () -> assertEquals(ZonedDateTime.parse(\"2024-03-31T03:00:00.000+02:00\").toInstant(), result));\n    }\n\n    @Test\n    void testEvenSecondDateAfterNowDSTBackward() {\n        var clock = Clock.fixed(\n                ZonedDateTime.parse(\"2024-10-27T02:59:59.999+02:00\")\n                        .toInstant(),\n                ZoneId.of(\"Europe/Vienna\"));\n        var before = clock.instant();\n        var result = DateBuilder.evenSecondDateAfterNow(clock).toInstant();\n\n        assertAll(\"DSTChange-1H\",\n                () -> assertEquals(ZonedDateTime.parse(\"2024-10-27T02:59:59.999+02:00\").toInstant(), before),\n                () -> assertEquals(ZonedDateTime.parse(\"2024-10-27T01:00:00.000Z\").toInstant(), result),\n                () -> assertEquals(ZonedDateTime.parse(\"2024-10-27T02:00:00.000+01:00\").toInstant(), result));\n    }\n\n    /*\n     * evenSecondDate tests\n     */\n\n    @Test\n    void testEvenSecondDate() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:55.000Z\"),\n                DateBuilder.evenSecondDate(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenSecondDateWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:55.000Z\"),\n                DateBuilder.evenSecondDate(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * evenSecondDateBefore tests\n     */\n\n    @Test\n    void testEvenSecondDateBefore() {\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:54.000Z\"),\n                DateBuilder.evenSecondDateBefore(Date.from(Instant.parse(\"2007-12-03T08:13:54.341Z\"))).toInstant());\n    }\n\n    @Test\n    void testEvenSecondDateBeforeWithoutProvidedDateCurrentDateRoundedToSeconds() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T08:13:54.341Z\"), ZoneOffset.UTC);\n        assertEquals(\n                Instant.parse(\"2007-12-03T08:13:54.000Z\"),\n                DateBuilder.evenSecondDateBefore(null, clock)\n                        .toInstant());\n    }\n\n    /*\n     * nextGivenMinuteDate tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 60, Integer.MAX_VALUE })\n    void testNextGivenMinuteDateWithInvalidSecondBaseShouldThrow(int minuteBase) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.nextGivenMinuteDate(null, minuteBase));\n    }\n\n    private static Stream<Arguments> nextGivenMinuteDateTestData() {\n        return Stream.of(\n                Arguments.of(\"2007-12-03T11:16:41.123Z\", 20, \"2007-12-03T11:20:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:36:41.123Z\", 20, \"2007-12-03T11:40:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:46:41.123Z\", 20, \"2007-12-03T12:00:00.000Z\"),\n\n                Arguments.of(\"2007-12-03T11:26:41.123Z\", 30, \"2007-12-03T11:30:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:36:41.123Z\", 30, \"2007-12-03T12:00:00.000Z\"),\n\n                Arguments.of(\"2007-12-03T11:16:41.123Z\", 17, \"2007-12-03T11:17:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:17:41.123Z\", 17, \"2007-12-03T11:34:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:52:41.123Z\", 17, \"2007-12-03T12:00:00.000Z\"),\n\n                Arguments.of(\"2007-12-03T11:52:41.123Z\", 5, \"2007-12-03T11:55:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:57:41.123Z\", 5, \"2007-12-03T12:00:00.000Z\"),\n\n                Arguments.of(\"2007-12-03T11:17:41.123Z\", 0, \"2007-12-03T12:00:00.000Z\"),\n                Arguments.of(\"2007-12-03T11:17:41.123Z\", 1, \"2007-12-03T11:18:00.000Z\"));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"nextGivenMinuteDateTestData\")\n    void testNextGivenMinuteDate(String input, int minuteBase, String expected) {\n        var instant = Instant.parse(input);\n        var result = DateBuilder.nextGivenMinuteDate(instant != null ? Date.from(instant) : null, minuteBase);\n        assertEquals(Instant.parse(expected), result.toInstant());\n    }\n\n    @Test\n    void testNextGivenMinuteDateWithNullDateShouldReturnCurrentDateRoundedToBaseMinute() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T10:15:30.123Z\"), ZoneOffset.UTC);\n        var result = DateBuilder.nextGivenMinuteDate(null, 0, clock);\n        assertEquals(Instant.parse(\"2007-12-03T11:00:00.000Z\"), result.toInstant());\n    }\n\n    /*\n     * nextGivenSecondDate tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 60, Integer.MAX_VALUE })\n    void testNextGivenSecondDateWithInvalidSecondBaseShouldThrow(int secondBase) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.nextGivenSecondDate(null, secondBase));\n    }\n\n    private static Stream<Arguments> nextGivenSecondDateTestData() {\n        return Stream.of(\n                Arguments.of(\"2007-12-03T10:15:30.123Z\", 0, \"2007-12-03T10:16:00.000Z\"),\n                Arguments.of(\"2007-12-03T10:15:30.123Z\", 1, \"2007-12-03T10:15:31.000Z\"),\n                Arguments.of(\"2007-12-03T10:15:54.256Z\", 13, \"2007-12-03T10:16:00.000Z\"),\n                Arguments.of(\"2007-12-03T10:15:30.256Z\", 13, \"2007-12-03T10:15:39.000Z\"),\n                Arguments.of(\"2007-12-03T10:15:30.000Z\", 59, \"2007-12-03T10:15:59.000Z\"));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"nextGivenSecondDateTestData\")\n    void testNextGivenSecondDate(String input, int secondBase, String expected) {\n        var instant = Instant.parse(input);\n        var result = DateBuilder.nextGivenSecondDate(instant != null ? Date.from(instant) : null, secondBase);\n        assertEquals(Instant.parse(expected), result.toInstant());\n    }\n\n    @Test\n    void testNextGivenSecondDateWithNullDateShouldReturnCurrentDateRoundedToBaseSecond() {\n        var clock = Clock.fixed(Instant.parse(\"2007-12-03T10:15:30.123Z\"), ZoneOffset.UTC);\n        var result = DateBuilder.nextGivenSecondDate(null, 0, clock);\n        assertEquals(Instant.parse(\"2007-12-03T10:16:00.000Z\"), result.toInstant());\n    }\n\n    /*\n     * translateTime tests\n     */\n\n    @Test\n    void testTranslate() {\n\n        TimeZone tz1 = TimeZone.getTimeZone(\"GMT-2:00\");\n        TimeZone tz2 = TimeZone.getTimeZone(\"GMT-4:00\");\n\n        Calendar vc = Calendar.getInstance(tz1);\n        vc.set(Calendar.YEAR, 2013);\n        vc.set(Calendar.MONTH, Calendar.JUNE);\n        vc.set(Calendar.DAY_OF_MONTH, 1);\n        vc.set(Calendar.HOUR_OF_DAY, 10);\n        vc.set(Calendar.MINUTE, 33);\n        vc.set(Calendar.SECOND, 12);\n        vc.set(Calendar.MILLISECOND, 0);\n\n        vc.setTime(translateTime(vc.getTime(), tz1, tz2));\n        assertEquals(12, vc.get(Calendar.HOUR_OF_DAY));\n\n        vc = Calendar.getInstance(tz2);\n        vc.set(Calendar.YEAR, 2013);\n        vc.set(Calendar.MONTH, Calendar.JUNE);\n        vc.set(Calendar.DAY_OF_MONTH, 1);\n        vc.set(Calendar.HOUR_OF_DAY, 10);\n        vc.set(Calendar.MINUTE, 33);\n        vc.set(Calendar.SECOND, 12);\n        vc.set(Calendar.MILLISECOND, 0);\n\n        vc.setTime(translateTime(vc.getTime(), tz2, tz1));\n        assertEquals(8, vc.get(Calendar.HOUR_OF_DAY));\n    }\n\n    private static Stream<Arguments> translateTimeTestData() {\n        return Stream.of(\n                Arguments.of(\n                        \"2013-06-01T10:33:12-02:00\",\n                        TimeZone.getTimeZone(\"GMT-2:00\"),\n                        TimeZone.getTimeZone(\"GMT-4:00\"),\n                        \"2013-06-01T12:33:12-02:00\"),\n                Arguments.of(\n                        \"2013-06-01T10:33:12-04:00\",\n                        TimeZone.getTimeZone(\"GMT-4:00\"),\n                        TimeZone.getTimeZone(\"GMT-2:00\"),\n                        \"2013-06-01T08:33:12-04:00\"));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"translateTimeTestData\")\n    void testTranslateTime(String input, TimeZone tzFrom, TimeZone tzTo, String expected) {\n        var zdt = ZonedDateTime.parse(input).withZoneSameInstant(tzFrom.toZoneId());\n        var result1 = translateTime(Date.from(zdt.toInstant()), tzFrom, tzTo);\n        assertEquals(ZonedDateTime.parse(expected).toInstant(), result1.toInstant());\n    }\n\n    /*\n     * validateDayOfWeek tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 0, 8, Integer.MAX_VALUE })\n    void testValidateDayOfWeekWithInvalidValueShouldThrow(int dayOfWeek) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateDayOfWeek(dayOfWeek));\n    }\n\n    private static Stream<Arguments> validateDayOfWeekTestData() {\n        return Stream.iterate(1, i -> i + 1)\n                .limit(7)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateDayOfWeekTestData\")\n    void testValidateDayOfWeek(int second) {\n        assertDoesNotThrow(() -> DateBuilder.validateDayOfWeek(second));\n    }\n\n    /*\n     * validateHour tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 24, Integer.MAX_VALUE })\n    void testValidateHourWithInvalidValueShouldThrow(int minute) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateHour(minute));\n    }\n\n    private static Stream<Arguments> validateHourTestData() {\n        return Stream.iterate(0, i -> i + 1)\n                .limit(24)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateHourTestData\")\n    void testValidateHour(int hour) {\n        assertDoesNotThrow(() -> DateBuilder.validateHour(hour));\n    }\n\n    /*\n     * validateMinutes tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 60, Integer.MAX_VALUE })\n    void testValidateMinuteWithInvalidValueShouldThrow(int minute) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateMinute(minute));\n    }\n\n    private static Stream<Arguments> validateMinuteTestData() {\n        return Stream.iterate(0, i -> i + 1)\n                .limit(60)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateMinuteTestData\")\n    void testValidateMinute(int minute) {\n        assertDoesNotThrow(() -> DateBuilder.validateMinute(minute));\n    }\n\n    /*\n     * validateSeconds tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 60, Integer.MAX_VALUE })\n    void testValidateSecondWithInvalidValueShouldThrow(int second) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateSecond(second));\n    }\n\n    private static Stream<Arguments> validateSecondsTestData() {\n        return Stream.iterate(0, i -> i + 1)\n                .limit(60)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateSecondsTestData\")\n    void testValidateSeconds(int second) {\n        assertDoesNotThrow(() -> DateBuilder.validateSecond(second));\n    }\n\n    /*\n     * validateDayOfMonth tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 0, 32, Integer.MAX_VALUE })\n    void testValidateDayOfMonthWithInvalidValueShouldThrow(int dayOfMonth) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateDayOfMonth(dayOfMonth));\n    }\n\n    private static Stream<Arguments> validateDayOfMonthTestData() {\n        return Stream.iterate(1, i -> i + 1)\n                .limit(31)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateDayOfMonthTestData\")\n    void testValidateDayOfMonth(int dayOfMonth) {\n        assertDoesNotThrow(() -> DateBuilder.validateDayOfMonth(dayOfMonth));\n    }\n\n    /*\n     * validateMonth tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, -1, 0, 13, Integer.MAX_VALUE })\n    void testValidateMonthWithInvalidValueShouldThrow(int month) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateMonth(month));\n    }\n\n    private static Stream<Arguments> validateMonthTestData() {\n        return Stream.iterate(1, i -> i + 1)\n                .limit(12)\n                .map(i -> Arguments.of(i));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"validateMonthTestData\")\n    void testValidateMonth(int month) {\n        assertDoesNotThrow(() -> DateBuilder.validateMonth(month));\n    }\n\n    /*\n     * validateYear tests\n     */\n\n    @ParameterizedTest\n    @ValueSource(ints = { Integer.MIN_VALUE, 1969, 1_000_000_000, Integer.MAX_VALUE })\n    void testValidateYearWithInvalidValueShouldThrow(int year) {\n        assertThrows(IllegalArgumentException.class, () -> DateBuilder.validateYear(year));\n    }\n\n    @ParameterizedTest\n    @ValueSource(ints = { 1970, 2024, 999_999_999 })\n    void testValidateYear(int year) {\n        assertDoesNotThrow(() -> DateBuilder.validateYear(year));\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/DefaultSchedulerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz;\n\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.JobDetailImpl;\nimport org.quartz.impl.StdSchedulerFactory;\n\n\n\n/**\n * DefaultSchedulerTest\n */\nclass DefaultSchedulerTest  {\n\n    @Test\n    void testAddJobNoTrigger() throws Exception {\n        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();\n        JobDetailImpl jobDetail = new JobDetailImpl();\n        jobDetail.setName(\"testjob\");\n\n        try {\n            scheduler.addJob(jobDetail, false);\n        } catch (SchedulerException e) {\n            assertThat(e.getMessage(), containsString(\"durable\"));\n        }\n\n        jobDetail.setDurability(true);\n        scheduler.addJob(jobDetail, false);\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/DisallowConcurrentExecutionJobTest.java",
    "content": "/* \r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n * \r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \r\n * use this file except in compliance with the License. You may obtain a copy \r\n * of the License at \r\n * \r\n *   http://www.apache.org/licenses/LICENSE-2.0 \r\n *   \r\n * Unless required by applicable law or agreed to in writing, software \r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \r\n * License for the specific language governing permissions and limitations \r\n * under the License.\r\n */\r\npackage org.quartz;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Properties;\r\nimport java.util.concurrent.CyclicBarrier;\r\nimport java.util.concurrent.TimeUnit;\r\nimport java.util.concurrent.atomic.AtomicInteger;\r\n\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.quartz.impl.StdSchedulerFactory;\r\nimport org.quartz.listeners.JobListenerSupport;\r\n\r\nimport static org.hamcrest.MatcherAssert.assertThat;\r\nimport static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;\r\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\r\n\r\n/**\r\n * Integration test for using DisallowConcurrentExecution annot.\r\n * \r\n * @author Zemian Deng <saltnlight5@gmail.com>\r\n */\r\nclass DisallowConcurrentExecutionJobTest {\r\n\t\r\n\tprivate static final long JOB_BLOCK_TIME = 300L;\r\n\t\r\n\tprivate static final String BARRIER = \"BARRIER\";\r\n\tprivate static final String DATE_STAMPS = \"DATE_STAMPS\";\r\n\t\r\n\t@DisallowConcurrentExecution\r\n\tpublic static class TestJob implements Job {\r\n\t\tpublic void execute(JobExecutionContext context) throws JobExecutionException {\r\n\t\t\ttry {\r\n\t\t\t\t@SuppressWarnings(\"unchecked\")\r\n\t\t\t\tList<Date> jobExecDates = (List<Date>)context.getScheduler().getContext().get(DATE_STAMPS);\r\n                                long firedAt = System.currentTimeMillis();\r\n\t\t\t\tjobExecDates.add(new Date(firedAt));\r\n                                long sleepTill = firedAt + JOB_BLOCK_TIME;\r\n                                for (long sleepFor = sleepTill - System.currentTimeMillis(); sleepFor > 0; sleepFor = sleepTill - System.currentTimeMillis()) {\r\n                                  Thread.sleep(sleepFor);\r\n                                }\r\n\t\t\t} catch (InterruptedException e) {\r\n\t\t\t\tthrow new JobExecutionException(\"Failed to pause job for testing.\");\r\n\t\t\t} catch (SchedulerException e) {\r\n\t\t\t\tthrow new JobExecutionException(\"Failed to lookup datestamp collection.\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\t\r\n\tpublic static class TestJobListener extends JobListenerSupport {\r\n\r\n\t\tprivate final AtomicInteger jobExCount = new AtomicInteger(0);\r\n\t\tprivate final int jobExecutionCountToSyncAfter;\r\n\t\t\r\n\t\tpublic TestJobListener(int jobExecutionCountToSyncAfter) {\r\n\t\t\tthis.jobExecutionCountToSyncAfter = jobExecutionCountToSyncAfter;\r\n\t\t}\r\n\t\t\r\n\t\tpublic String getName() {\r\n\t\t\treturn \"TestJobListener\";\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic void jobWasExecuted(JobExecutionContext context,\r\n\t\t\t\tJobExecutionException jobException) {\r\n\t\t\tif(jobExCount.incrementAndGet() == jobExecutionCountToSyncAfter) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tCyclicBarrier barrier =  (CyclicBarrier)context.getScheduler().getContext().get(BARRIER);\r\n\t\t\t\t\tbarrier.await(125, TimeUnit.SECONDS);\r\n\t\t\t\t} catch (Throwable e) {\r\n\t\t\t\t\te.printStackTrace();\r\n\t\t\t\t\tthrow new AssertionError(\"Await on barrier was interrupted: \" + e.toString());\r\n\t\t\t\t} \r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\t\r\n        @Test\r\n\t\tvoid testNoConcurrentExecOnSameJob() throws Exception {\r\n\r\n\t\tList<Date> jobExecDates = Collections.synchronizedList(new ArrayList<Date>());\r\n\t\tCyclicBarrier barrier = new CyclicBarrier(2);\r\n\t\t\r\n\t\tDate startTime = new Date(System.currentTimeMillis() + 100); // make the triggers fire at the same time.\r\n\t\t\r\n\t\tJobDetail job1 = JobBuilder.newJob(TestJob.class).withIdentity(\"job1\").build();\r\n\t\tTrigger trigger1 = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule())\r\n\t\t\t\t.startAt(startTime).build();\r\n\r\n\t\tTrigger trigger2 = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule())\r\n\t\t\t\t.startAt(startTime).forJob(job1.getKey()).build();\r\n\r\n\t\tProperties props = new Properties();\r\n\t\tprops.setProperty(\"org.quartz.scheduler.idleWaitTime\", \"1500\");\r\n\t\tprops.setProperty(\"org.quartz.threadPool.threadCount\", \"2\");\r\n\t\tScheduler scheduler = new StdSchedulerFactory(props).getScheduler();\r\n\t\tscheduler.getContext().put(BARRIER, barrier);\r\n\t\tscheduler.getContext().put(DATE_STAMPS, jobExecDates);\r\n\t\tscheduler.getListenerManager().addJobListener(new TestJobListener(2));\r\n\t\tscheduler.scheduleJob(job1, trigger1);\r\n\t\tscheduler.scheduleJob(trigger2);\r\n\t\tscheduler.start();\r\n\t\t\r\n\t\tbarrier.await(125, TimeUnit.SECONDS);\r\n\t\t\r\n\t\tscheduler.shutdown(true);\r\n\t\t\r\n                assertThat(jobExecDates, hasSize(2));\r\n                long fireTimeTrigger1 = jobExecDates.get(0).getTime();\r\n                long fireTimeTrigger2 = jobExecDates.get(1).getTime();\r\n                assertThat(fireTimeTrigger2 - fireTimeTrigger1, greaterThanOrEqualTo(JOB_BLOCK_TIME));\r\n\t}\r\n\t\r\n\t/** QTZ-202 */\r\n        @Test\r\n\t\tvoid testNoConcurrentExecOnSameJobWithBatching() throws Exception {\r\n\r\n\t\tList<Date> jobExecDates = Collections.synchronizedList(new ArrayList<Date>());\r\n\t\tCyclicBarrier barrier = new CyclicBarrier(2);\r\n\t\t\r\n\t\tDate startTime = new Date(System.currentTimeMillis() + 100); // make the triggers fire at the same time.\r\n\t\t\r\n\t\tJobDetail job1 = JobBuilder.newJob(TestJob.class).withIdentity(\"job1\").build();\r\n\t\tTrigger trigger1 = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule())\r\n\t\t\t\t.startAt(startTime).build();\r\n\r\n\t\tTrigger trigger2 = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule())\r\n\t\t\t\t.startAt(startTime).forJob(job1.getKey()).build();\r\n\r\n\t\tProperties props = new Properties();\r\n\t\tprops.setProperty(\"org.quartz.scheduler.idleWaitTime\", \"1500\");\r\n\t\tprops.setProperty(\"org.quartz.scheduler.batchTriggerAcquisitionMaxCount\", \"2\");\r\n\t\tprops.setProperty(\"org.quartz.threadPool.threadCount\", \"2\");\r\n\t\tScheduler scheduler = new StdSchedulerFactory(props).getScheduler();\r\n\t\tscheduler.getContext().put(BARRIER, barrier);\r\n\t\tscheduler.getContext().put(DATE_STAMPS, jobExecDates);\r\n\t\tscheduler.getListenerManager().addJobListener(new TestJobListener(2));\r\n\t\tscheduler.scheduleJob(job1, trigger1);\r\n\t\tscheduler.scheduleJob(trigger2);\r\n\t\tscheduler.start();\r\n\t\t\r\n\t\tbarrier.await(125, TimeUnit.SECONDS);\r\n\t\t\r\n\t\tscheduler.shutdown(true);\r\n\t\t\r\n                assertThat(jobExecDates, hasSize(2));\r\n                long fireTimeTrigger1 = jobExecDates.get(0).getTime();\r\n                long fireTimeTrigger2 = jobExecDates.get(1).getTime();\r\n                assertThat(fireTimeTrigger2 - fireTimeTrigger1, greaterThanOrEqualTo(JOB_BLOCK_TIME));\r\n\t}\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/FlakyJdbcSchedulerTest.java",
    "content": "package org.quartz;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.SchedulerRepository;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JobStoreTX;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.utils.ConnectionProvider;\nimport org.quartz.utils.DBConnectionManager;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic class FlakyJdbcSchedulerTest extends AbstractSchedulerTest {\n\n    private Random random = new Random();\n    private float createFailureProb = 0.0f;\n    private float preCommitFailureProb = 0.0f;\n    private float postCommitFailureProb = 0.0f;\n\n    @MethodSource(\"data\")\n    public static Stream<Arguments> data() {\n        return Stream.of(\n                Arguments.of(0f, 0f, 0f),\n                Arguments.of(0.2f, 0f, 0f),\n                Arguments.of(0f, 0.2f, 0f),\n                Arguments.of(0f, 0f, 0.2f),\n                Arguments.of(0.2f, 0.2f, 0.2f)\n        );\n    }\n\n    @Override\n    protected Scheduler createScheduler(String name, int threadPoolSize) throws SchedulerException {\n        try {\n            DBConnectionManager.getInstance().addConnectionProvider(name, new FlakyConnectionProvider(name));\n        } catch (SQLException ex) {\n            throw new SchedulerException(\"Failed to create scheduler\", ex);\n        }\n\n        JobStoreTX jobStore = new JobStoreTX();\n        jobStore.setDataSource(name);\n        jobStore.setTablePrefix(\"QRTZ_\");\n        jobStore.setInstanceId(\"AUTO\");\n        jobStore.setDbRetryInterval(50);\n\n        DirectSchedulerFactory.getInstance().createScheduler(\n                name + \"Scheduler\",\n                \"AUTO\",\n                new SimpleThreadPool(threadPoolSize, Thread.NORM_PRIORITY),\n                jobStore,\n                null,\n                0,\n                -1,\n                50\n        );\n\n        return SchedulerRepository.getInstance().lookup(name + \"Scheduler\");\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"data\")\n    void testTriggerFiring(float createFailureProb, float preCommitFailureProb, float postCommitFailureProb) throws Exception {\n        this.createFailureProb = createFailureProb;\n        this.preCommitFailureProb = preCommitFailureProb;\n        this.postCommitFailureProb = postCommitFailureProb;\n        this.random = new Random();\n\n        final int jobCount = 100;\n        final int execCount = 5;\n        Scheduler scheduler = createScheduler(\"testTriggerFiring\", 2);\n\n        try {\n            for (int i = 0; i < jobCount; i++) {\n                String jobName = \"myJob\" + i;\n                JobDetail jobDetail = JobBuilder.newJob(TestJob.class)\n                        .withIdentity(jobName, \"myJobGroup\")\n                        .usingJobData(\"data\", 0)\n                        .storeDurably()\n                        .requestRecovery()\n                        .build();\n\n                Trigger trigger = TriggerBuilder.newTrigger()\n                        .withIdentity(\"triggerName\" + i, \"triggerGroup\")\n                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).withRepeatCount(execCount - 1))\n                        .build();\n\n                if (!scheduler.checkExists(jobDetail.getKey())) {\n                    scheduler.scheduleJob(jobDetail, trigger);\n                }\n            }\n\n            scheduler.start();\n\n            for (int i = 0; i < TimeUnit.MINUTES.toSeconds(5); i++) {\n                int doneCount = 0;\n                for (int j = 0; j < jobCount; j++) {\n                    JobDetail jobDetail = scheduler.getJobDetail(new JobKey(\"myJob\" + j, \"myJobGroup\"));\n                    if (jobDetail != null && jobDetail.getJobDataMap().getInt(\"data\") >= execCount) {\n                        doneCount++;\n                    }\n                }\n                if (doneCount == jobCount) {\n                    return;\n                }\n                TimeUnit.SECONDS.sleep(1);\n            }\n            fail(\"Not all jobs completed as expected.\");\n        } finally {\n            scheduler.shutdown(true);\n        }\n    }\n\n    @PersistJobDataAfterExecution\n    @DisallowConcurrentExecution\n    public static class TestJob implements Job {\n        public void execute(JobExecutionContext context) {\n            JobDataMap dataMap = context.getJobDetail().getJobDataMap();\n            int val = dataMap.getInt(\"data\") + 1;\n            dataMap.put(\"data\", val);\n        }\n    }\n\n    private void createFailure() throws SQLException {\n        if (random.nextFloat() < createFailureProb) {\n            throw new SQLException(\"FlakyConnection failed on you on creation.\");\n        }\n    }\n\n    private void preCommitFailure() throws SQLException {\n        if (random.nextFloat() < preCommitFailureProb) {\n            throw new SQLException(\"FlakyConnection failed on you pre-commit.\");\n        }\n    }\n\n    private void postCommitFailure() throws SQLException {\n        if (random.nextFloat() < postCommitFailureProb) {\n            throw new SQLException(\"FlakyConnection failed on you post-commit.\");\n        }\n    }\n\n    private class FlakyConnectionProvider implements ConnectionProvider {\n        private final Thread safeThread;\n        private final String delegateName;\n\n        private FlakyConnectionProvider(String name) throws SQLException {\n            this.delegateName = \"delegate_\" + name;\n            this.safeThread = Thread.currentThread();\n            JdbcQuartzTestUtilities.createDatabase(delegateName, DatabaseType.DERBY);\n        }\n\n        @Override\n        public Connection getConnection() throws SQLException {\n            if (Thread.currentThread() == safeThread) {\n                return DBConnectionManager.getInstance().getConnection(delegateName);\n            } else {\n                createFailure();\n                return (Connection) Proxy.newProxyInstance(\n                        Connection.class.getClassLoader(),\n                        new Class[]{Connection.class},\n                        new FlakyConnectionInvocationHandler(DBConnectionManager.getInstance().getConnection(delegateName))\n                );\n            }\n        }\n\n        @Override\n        public void shutdown() throws SQLException {\n            DBConnectionManager.getInstance().shutdown(delegateName);\n            JdbcQuartzTestUtilities.destroyDatabase(delegateName, DatabaseType.DERBY);\n            JdbcQuartzTestUtilities.shutdownDatabase(delegateName, DatabaseType.DERBY);\n        }\n\n        @Override\n        public void initialize() throws SQLException {\n            // No-op\n        }\n    }\n\n    private class FlakyConnectionInvocationHandler implements InvocationHandler {\n        private final Connection delegate;\n\n        public FlakyConnectionInvocationHandler(Connection delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n            if (\"commit\".equals(method.getName())) {\n                preCommitFailure();\n                method.invoke(delegate, args);\n                postCommitFailure();\n                return null;\n            } else {\n                return method.invoke(delegate, args);\n            }\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/test/java/org/quartz/InterruptableJobTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.StdSchedulerFactory;\n\n/**\n * Test job interruption\n */\npublic class InterruptableJobTest  {\n\n    static final CyclicBarrier sync = new CyclicBarrier(2);\n\n    public static class TestInterruptableJob implements InterruptableJob {\n\n        public static final AtomicBoolean interrupted = new AtomicBoolean(false);\n        \n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n            System.out.println(\"TestInterruptableJob is executing.\");\n            try {\n                sync.await(); // wait for test thread to notice the job is now running\n            } catch (InterruptedException e1) {\n            } catch (BrokenBarrierException e1) {\n            }\n            for(int i=0; i < 200; i++) {\n                try {\n                    Thread.sleep(50); // simulate being busy for a while, then checking interrupted flag...\n                } catch (InterruptedException ignore) { }\n                if(TestInterruptableJob.interrupted.get()) {\n                    System.out.println(\"TestInterruptableJob main loop detected interrupt signal.\");\n                    break;\n                }\n            }\n            try {\n                System.out.println(\"TestInterruptableJob exiting with interrupted = \" + interrupted);\n                sync.await();\n            } catch (InterruptedException e) {\n            } catch (BrokenBarrierException e) {\n            }\n        }\n\n        public void interrupt() throws UnableToInterruptJobException {\n            TestInterruptableJob.interrupted.set(true);\n            System.out.println(\"TestInterruptableJob.interrupt() called.\");\n        }\n    }\n    \n  /*  @Override\n    protected void setUp() throws Exception {\n    }*/\n\n    @Test\n    void testJobInterruption() throws Exception {\n        \n        // create a simple scheduler\n        \n        Properties config = new Properties();\n        config.setProperty(\"org.quartz.scheduler.instanceName\", \"InterruptableJobTest_Scheduler\");\n        config.setProperty(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        config.setProperty(\"org.quartz.threadPool.threadCount\", \"2\");\n        config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        Scheduler sched = new StdSchedulerFactory(config).getScheduler();\n        sched.start();\n\n        // add a job with a trigger that will fire immediately\n        \n        JobDetail job = newJob()\n            .ofType(TestInterruptableJob.class)\n            .withIdentity(\"j1\")\n            .build();\n\n        Trigger trigger = newTrigger()\n            .withIdentity(\"t1\")\n            .forJob(job)\n            .startNow()\n            .build();\n\n        sched.scheduleJob(job, trigger);\n        \n        sync.await();  // make sure the job starts running...\n        \n        List<JobExecutionContext> executingJobs = sched.getCurrentlyExecutingJobs();\n\n        assertEquals(1, executingJobs.size(), \"Number of executing jobs should be 1 \");\n        \n        JobExecutionContext jec = executingJobs.get(0);\n        \n        boolean interruptResult = sched.interrupt(jec.getFireInstanceId());\n        \n        sync.await(); // wait for the job to terminate\n\n        assertTrue(interruptResult, \"Expected successful result from interruption of job \");\n\n        assertTrue(TestInterruptableJob.interrupted.get(), \"Expected interrupted flag to be set on job class \");\n        \n        sched.clear();\n\n        sched.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/JdbcSchedulerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz;\n\nimport java.sql.SQLException;\n\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.SchedulerRepository;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JobStoreTX;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.simpl.SimpleThreadPool;\n\npublic class JdbcSchedulerTest extends AbstractSchedulerTest {\n    \n    protected DatabaseType getDatabaseType() {\n        return DatabaseType.DERBY;\n    }\n\n    @Override\n    protected Scheduler createScheduler(String name, int threadPoolSize) throws SchedulerException {\n        try {\n            JdbcQuartzTestUtilities.createDatabase(name + getDatabaseType().name(), getDatabaseType());\n        } catch (SQLException e) {\n            throw new AssertionError(e);\n        }\n        JobStoreTX jobStore = new JobStoreTX();\n        jobStore.setDataSource(name + getDatabaseType().name());\n        jobStore.setTablePrefix(\"QRTZ_\");\n        jobStore.setInstanceId(\"AUTO\");\n        DirectSchedulerFactory.getInstance().createScheduler(name + \"Scheduler\", \"AUTO\", new SimpleThreadPool(threadPoolSize, Thread.NORM_PRIORITY), jobStore);\n        return SchedulerRepository.getInstance().lookup(name + \"Scheduler\");\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/JobBuilderTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.JobKey.jobKey;\n\n\n/**\n * Test JobBuilder functionality \n */\npublic class JobBuilderTest  {\n\n\n    @SuppressWarnings(\"deprecation\")\n    public static class TestStatefulJob implements StatefulJob {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n\n    public static class TestJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n    \n    @DisallowConcurrentExecution\n    @PersistJobDataAfterExecution\n    public static class TestAnnotatedJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n\n /*   @Override\n    protected void setUp() throws Exception {\n    }*/\n\n    @Test\n    void testJobBuilder() throws Exception {\n        \n        JobDetail job = newJob()\n            .ofType(TestJob.class)\n            .withIdentity(\"j1\")\n            .storeDurably()\n            .build();\n\n        assertEquals(\"j1\", job.getKey().getName(), \"Unexpected job name: \" + job.getKey().getName());\n        assertEquals(JobKey.DEFAULT_GROUP, job.getKey().getGroup(), \"Unexpected job group: \" + job.getKey().getGroup());\n        assertEquals(job.getKey(), jobKey(\"j1\"), \"Unexpected job key: \" + job.getKey());\n        assertNull(job.getDescription(), \"Unexpected job description: \" + job.getDescription());\n        assertTrue(job.isDurable(), \"Expected isDurable == true \");\n        assertFalse(job.requestsRecovery(), \"Expected requestsRecovery == false \");\n        assertFalse(job.isConcurrentExecutionDisallowed(), \"Expected isConcurrentExecutionDisallowed == false \");\n        assertFalse(job.isPersistJobDataAfterExecution(), \"Expected isPersistJobDataAfterExecution == false \");\n        assertEquals(job.getJobClass(), TestJob.class, \"Unexpected job class: \" + job.getJobClass());\n        \n        job = newJob()\n            .ofType(TestAnnotatedJob.class)\n            .withIdentity(\"j1\")\n            .withDescription(\"my description\")\n            .storeDurably(true)\n            .requestRecovery()\n            .build();\n\n        assertEquals(\"my description\", job.getDescription(), \"Unexpected job description: \" + job.getDescription());\n        assertTrue(job.isDurable(), \"Expected isDurable == true \");\n        assertTrue(job.requestsRecovery(), \"Expected requestsRecovery == true \");\n        assertTrue(job.isConcurrentExecutionDisallowed(), \"Expected isConcurrentExecutionDisallowed == true \");\n        assertTrue(job.isPersistJobDataAfterExecution(), \"Expected isPersistJobDataAfterExecution == true \");\n        \n        job = newJob()\n            .ofType(TestStatefulJob.class)\n            .withIdentity(\"j1\", \"g1\")\n            .requestRecovery(false)\n            .build();\n\n        assertEquals(\"g1\", job.getKey().getGroup(), \"Unexpected job group: \" + job.getKey().getName());\n        assertFalse(job.isDurable(), \"Expected isDurable == false \");\n        assertFalse(job.requestsRecovery(), \"Expected requestsRecovery == false \");\n        assertTrue(job.isConcurrentExecutionDisallowed(), \"Expected isConcurrentExecutionDisallowed == true \");\n        assertTrue(job.isPersistJobDataAfterExecution(), \"Expected isPersistJobDataAfterExecution == true \");\n     \n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/JobDataMapTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\n/**\n * Unit test for JobDataMap serialization backwards compatibility.\n */\npublic class JobDataMapTest extends SerializationTestSupport {\n    private static final String[] VERSIONS = new String[] {\"1.4.5\", \"1.5.1\", \"2.1\"};\n    \n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @Override\n    protected Object getTargetObject() {\n        JobDataMap m = new JobDataMap();\n        m.put(\"key\", Integer.valueOf(5));\n        return m;\n    }\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        JobDataMap targetMap = (JobDataMap)target;\n        JobDataMap deserializedMap = (JobDataMap)deserialized;\n        \n        assertNotNull(deserializedMap);\n        assertEquals(targetMap.getWrappedMap(), deserializedMap.getWrappedMap());\n        assertEquals(targetMap.getAllowsTransientData(), deserializedMap.getAllowsTransientData());\n        assertEquals(targetMap.isDirty(), deserializedMap.isDirty());\n    }\n    \n    public static void main(String[] args) throws Exception {\n\t\tnew JobDataMapTest().writeJobDataFile(\"2.1\");\n\t}\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/JobDetailTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.JobDetailImpl;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n\n/**\n * Unit test for JobDetail.\n */\npublic class JobDetailTest  {\n\n    @PersistJobDataAfterExecution\n    public class SomePersistentJob implements Job {\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n       }\n    }\n\n    public class SomeExtendedPersistentJob extends SomePersistentJob {\n    }\n\n    @DisallowConcurrentExecution\n    public class SomeNonConcurrentJob implements Job {\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n        }\n    }\n\n    public class SomeExtendedNonConcurrentJob extends SomeNonConcurrentJob {\n    }\n\n    @DisallowConcurrentExecution\n    @PersistJobDataAfterExecution\n    public class SomeNonConcurrentPersistentJob implements Job {\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n        }\n    }\n\n    public class SomeExtendedNonConcurrentPersistentJob extends SomeNonConcurrentPersistentJob {\n    }\n\n    public class SomeStatefulJob implements StatefulJob {\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n        }\n    }\n\n    public class SomeExtendedStatefulJob extends SomeStatefulJob {\n    }\n\n    @Test\n    void testClone() {\n        JobDetailImpl jobDetail = new JobDetailImpl();\n        jobDetail.setName(\"hi\");\n        \n        JobDetail clonedJobDetail = (JobDetail)jobDetail.clone();\n        assertEquals(clonedJobDetail, jobDetail);\n        \n    }\n    @Test\n    void testAnnotationDetection() {\n        JobDetailImpl jobDetail = new JobDetailImpl();\n        jobDetail.setName(\"hi\");\n\n        jobDetail.setJobClass(SomePersistentJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomePersistentJob to be persistent\");\n        assertFalse(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomePersistentJob to not disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeNonConcurrentJob.class);\n        assertFalse(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeNonConcurrentJob to not be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeNonConcurrentJob to disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeNonConcurrentPersistentJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeNonConcurrentPersistentJob to be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeNonConcurrentPersistentJob to disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeStatefulJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeStatefulJob to be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeStatefulJob to disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeExtendedPersistentJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeExtendedPersistentJob to be persistent\");\n        assertFalse(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeExtendedPersistentJob to not disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeExtendedNonConcurrentJob.class);\n        assertFalse(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeExtendedNonConcurrentJob to not be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeExtendedNonConcurrentJob to disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeExtendedNonConcurrentPersistentJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeExtendedNonConcurrentPersistentJob to be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeExtendedNonConcurrentPersistentJob to disallow concurrent execution\");\n\n        jobDetail.setJobClass(SomeExtendedStatefulJob.class);\n        assertTrue(jobDetail.isPersistJobDataAfterExecution(), \"Expecting SomeExtendedStatefulJob to be persistent\");\n        assertTrue(jobDetail.isConcurrentExecutionDisallowed(), \"Expecting SomeExtendedStatefulJob to disallow concurrent execution\");\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/MonthlyCalendarTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.util.Calendar;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.calendar.MonthlyCalendar;\n\n/**\n * Unit test for MonthlyCalendar\n */\npublic class MonthlyCalendarTest  {\n\n    /**\n     * Tests whether greater than the 7th of the month causes infinite looping. \n     * See: QUARTZ-636\n     */\n    @Test\n    void testForInfiniteLoop() {\n        MonthlyCalendar monthlyCalendar = new MonthlyCalendar();\n\n        for(int i=1; i<9; i++) {\n            monthlyCalendar.setDayExcluded(i, true);\n        }\n        Calendar c = Calendar.getInstance();\n        c.set(2007, 11, 8, 12, 0, 0);\n\n        monthlyCalendar.getNextIncludedTime(c.getTime().getTime());\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/PriorityTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz;\n\nimport java.util.Calendar;\nimport java.util.Properties;\nimport java.util.concurrent.CountDownLatch;\n\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.JobDetailImpl;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Test Trigger priority support.\n */\nclass PriorityTest  {\n\n    private static CountDownLatch latch;\n    private static StringBuffer result;\n\n    @SuppressWarnings(\"deprecation\")\n    public static class TestJob implements StatefulJob {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n            result.append(context.getTrigger().getKey().getName());\n            latch.countDown();\n        }\n    }\n\n    @BeforeEach\n    protected void setUp() {\n        PriorityTest.latch = new CountDownLatch(2);\n        PriorityTest.result = new StringBuffer();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testSameDefaultPriority() throws Exception {\n        Properties config = new Properties();\n        config.setProperty(\"org.quartz.threadPool.threadCount\", \"1\");\n        config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n\n        Scheduler sched = new StdSchedulerFactory(config).getScheduler();\n\n        Calendar cal = Calendar.getInstance();\n        cal.add(Calendar.SECOND, 1);\n\n        MutableTrigger trig1 = new SimpleTriggerImpl(\"T1\", null, cal.getTime());\n        MutableTrigger trig2 = new SimpleTriggerImpl(\"T2\", null, cal.getTime());\n\n        JobDetail jobDetail = new JobDetailImpl(\"JD\", null, TestJob.class);\n\n        sched.scheduleJob(jobDetail, trig1);\n\n        trig2.setJobKey(new JobKey(jobDetail.getKey().getName()));\n        sched.scheduleJob(trig2);\n\n        sched.start();\n\n        latch.await();\n\n        assertEquals(\"T1T2\", result.toString());\n\n        sched.shutdown();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    void testDifferentPriority() throws Exception {\n        Properties config = new Properties();\n        config.setProperty(\"org.quartz.threadPool.threadCount\", \"1\");\n        config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n\n        Scheduler sched = new StdSchedulerFactory(config).getScheduler();\n\n        Calendar cal = Calendar.getInstance();\n        cal.add(Calendar.SECOND, 1);\n\n        MutableTrigger trig1 = new SimpleTriggerImpl(\"T1\", null, cal.getTime());\n        trig1.setPriority(5);\n\n        MutableTrigger trig2 = new SimpleTriggerImpl(\"T2\", null, cal.getTime());\n        trig2.setPriority(10);\n\n        JobDetail jobDetail = new JobDetailImpl(\"JD\", null, TestJob.class);\n\n        sched.scheduleJob(jobDetail, trig1);\n\n        trig2.setJobKey(new JobKey(jobDetail.getKey().getName(), null));\n        sched.scheduleJob(trig2);\n\n        sched.start();\n\n        latch.await();\n\n        assertEquals(\"T2T1\", result.toString());\n\n        sched.shutdown();\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/Qtz205SchedulerListenerTest.java",
    "content": "/*\r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\r\n * use this file except in compliance with the License. You may obtain a copy\r\n * of the License at\r\n *\r\n *   http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r\n * License for the specific language governing permissions and limitations\r\n * under the License.\r\n */\r\npackage org.quartz;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.quartz.JobBuilder.newJob;\r\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\r\nimport static org.quartz.TriggerBuilder.newTrigger;\r\n\r\nimport java.util.Properties;\r\n\r\n\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.quartz.Trigger.CompletedExecutionInstruction;\r\nimport org.quartz.impl.StdSchedulerFactory;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * A unit test to reproduce QTZ-205 bug:\r\n * A TriggerListener vetoed job will affect SchedulerListener's triggerFinalized() notification. \r\n * \r\n * @author Zemian Deng <saltnlight5@gmail.com>\r\n */\r\nclass Qtz205SchedulerListenerTest {\r\n\tprivate static Logger logger = LoggerFactory.getLogger(Qtz205SchedulerListenerTest.class);\r\n\t\r\n\tpublic static class Qtz205Job implements Job {\r\n\t\tprivate static volatile int jobExecutionCount = 0;\t\r\n\t\tpublic void execute(JobExecutionContext context) throws JobExecutionException {\r\n\t\t\tjobExecutionCount++;\r\n\t\t\tlogger.info(\"Job executed. jobExecutionCount=\" + jobExecutionCount);\r\n\t\t}\r\n\t\t\r\n\t}\r\n\t\r\n\tpublic static class Qtz205TriggerListener implements TriggerListener {\r\n\t\tprivate volatile int fireCount;\r\n\t\tpublic int getFireCount() {\r\n\t\t\treturn fireCount;\r\n\t\t}\r\n\t\tpublic String getName() {\r\n\t\t\treturn \"Qtz205TriggerListener\";\r\n\t\t}\r\n\r\n\t\tpublic void triggerFired(Trigger trigger, JobExecutionContext context) {\r\n\t\t\tfireCount++;\r\n\t\t\tlogger.info(\"Trigger fired. count \" + fireCount);\r\n\t\t}\r\n\r\n\t\tpublic boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {\r\n\t\t\tif (fireCount >= 3) {\r\n\t\t\t\tlogger.info(\"Job execution vetoed.\");\r\n\t\t\t\treturn true;\r\n\t\t\t} else {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void triggerMisfired(Trigger trigger) {\r\n\t\t}\r\n\r\n\t\tpublic void triggerComplete(Trigger trigger,\r\n\t\t\t\tJobExecutionContext context,\r\n\t\t\t\tCompletedExecutionInstruction triggerInstructionCode) {\r\n\t\t}\r\n\t\t\r\n\t}\r\n\t\r\n\tpublic static class Qtz205ScheListener implements SchedulerListener {\r\n\t\tprivate int triggerFinalizedCount;\r\n\t\tpublic int getTriggerFinalizedCount() {\r\n\t\t\treturn triggerFinalizedCount;\r\n\t\t}\r\n\t\tpublic void jobScheduled(Trigger trigger) {\r\n\t\t}\r\n\r\n\t\tpublic void jobUnscheduled(TriggerKey triggerKey) {\r\n\t\t}\r\n\r\n\t\tpublic void triggerFinalized(Trigger trigger) {\r\n\t\t\ttriggerFinalizedCount ++;\r\n\t\t\tlogger.info(\"triggerFinalized \" + trigger);\r\n\t\t}\r\n\r\n\t\tpublic void triggerPaused(TriggerKey triggerKey) {\r\n\t\t}\r\n\r\n\t\tpublic void triggersPaused(String triggerGroup) {\t\r\n\t\t}\r\n\r\n\t\tpublic void triggerResumed(TriggerKey triggerKey) {\r\n\t\t}\r\n\r\n\t\tpublic void triggersResumed(String triggerGroup) {\r\n\t\t}\r\n\r\n\t\tpublic void jobAdded(JobDetail jobDetail) {\r\n\t\t}\r\n\r\n\t\tpublic void jobDeleted(JobKey jobKey) {\r\n\t\t}\r\n\r\n\t\tpublic void jobPaused(JobKey jobKey) {\r\n\t\t}\r\n\r\n\t\tpublic void jobsPaused(String jobGroup) {\r\n\t\t}\r\n\r\n\t\tpublic void jobResumed(JobKey jobKey) {\r\n\t\t}\r\n\r\n\t\tpublic void jobsResumed(String jobGroup) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic void schedulerError(String msg, SchedulerException cause) {\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic void schedulerInStandbyMode() {\r\n\t\t}\r\n\r\n\t\tpublic void schedulerStarted() {\r\n\t\t}\r\n\t\t\r\n\t\tpublic void schedulerStarting() {\r\n\t\t}\r\n\r\n\t\tpublic void schedulerShutdown() {\r\n\t\t}\r\n\r\n\t\tpublic void schedulerShuttingdown() {\r\n\t\t}\r\n\r\n\t\tpublic void schedulingDataCleared() {\r\n\t\t}\r\n\t}\r\n\t\r\n\t/** QTZ-205 */\r\n\r\n\t@Test\r\n\tvoid testTriggerFinalized() throws Exception {\r\n\t\tQtz205TriggerListener triggerListener = new Qtz205TriggerListener();\r\n\t\tQtz205ScheListener schedulerListener = new Qtz205ScheListener();\r\n\t\tProperties props = new Properties();\r\n\t\tprops.setProperty(\"org.quartz.scheduler.idleWaitTime\", \"1500\");\r\n\t\tprops.setProperty(\"org.quartz.threadPool.threadCount\", \"2\");\r\n\t\tScheduler scheduler = new StdSchedulerFactory(props).getScheduler();\r\n\t\tscheduler.getListenerManager().addSchedulerListener(schedulerListener);\r\n\t\tscheduler.getListenerManager().addTriggerListener(triggerListener);\r\n\t\tscheduler.start();\r\n\t\tscheduler.standby();\r\n\t\t\r\n\t\tJobDetail job = newJob(Qtz205Job.class).withIdentity(\"test\").build();\r\n\t\tTrigger trigger = newTrigger().withIdentity(\"test\")\r\n\t\t\t\t.withSchedule(simpleSchedule().withIntervalInMilliseconds(250).withRepeatCount(2))\r\n\t\t\t\t.build();\r\n\t\tscheduler.scheduleJob(job, trigger);\r\n\t\tscheduler.start();\r\n\t\tThread.sleep(5000);\r\n\t\t\r\n\t\tscheduler.shutdown(true);\r\n\r\n\t\tassertEquals(2, Qtz205Job.jobExecutionCount);\r\n\t\tassertEquals(3, triggerListener.getFireCount());\r\n\t\tassertEquals(1, schedulerListener.getTriggerFinalizedCount());\r\n\t}\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/Quartz601Test.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.text.ParseException;\nimport java.util.Set;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\n\nclass Quartz601Test  {\n    @Test\n    void testNormal() {\n        for(int i=0; i<6; i++) {\n            assertParsesForField(\"0 15 10 * * ? 2005\", i);\n        }\n    }\n    void testSecond() {\n          assertParsesForField(\"58-4 5 21 ? * MON-FRI\", 0);\n    }\n    void testMinute() {\n          assertParsesForField(\"0 58-4 21 ? * MON-FRI\", 1);\n    }\n    void testHour() {\n          assertParsesForField(\"0 0/5 21-3 ? * MON-FRI\", 2);\n    }\n    void testDayOfWeekNumber() {\n          assertParsesForField(\"58 5 21 ? * 6-2\", 5);\n    }\n    void testDayOfWeek() {\n          assertParsesForField(\"58 5 21 ? * FRI-TUE\", 5);\n    }\n    void testDayOfMonth() {\n          assertParsesForField(\"58 5 21 28-5 1 ?\", 3);\n    }\n    void testMonth() {\n          assertParsesForField(\"58 5 21 ? 11-2 FRI\", 4);\n    }\n    void testAmbiguous() {\n          assertParsesForField(\"0 0 14-6 ? * FRI-MON\", 2);\n          assertParsesForField(\"0 0 14-6 ? * FRI-MON\", 5);\n\n          assertParsesForField(\"55-3 56-2 6 ? * FRI\", 0);\n          assertParsesForField(\"55-3 56-2 6 ? * FRI\", 1);\n    }\n\n    private void assertParsesForField(String expression, int constant) {\n        try {\n            CronExpression cronExpression = new CronExpression(expression);\n            Set<Integer> set = cronExpression.getSet(constant);\n            assert set != null;\n            if(set.isEmpty()) {\n                fail(\"Empty field [\"+constant+\"] returned for \" + expression);\n            }\n        } catch(ParseException pe) {\n            fail(\"Exception thrown during parsing: \" + pe);\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/RAMSchedulerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz;\n\nimport java.util.Properties;\n\nimport org.quartz.impl.StdSchedulerFactory;\n\npublic class RAMSchedulerTest extends AbstractSchedulerTest {\n\n    @Override\n    protected Scheduler createScheduler(String name, int threadPoolSize) throws SchedulerException {\n        Properties config = new Properties();\n        config.setProperty(\"org.quartz.scheduler.instanceName\", name + \"Scheduler\");\n        config.setProperty(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        config.setProperty(\"org.quartz.threadPool.threadCount\", Integer.toString(threadPoolSize));\n        config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        return new StdSchedulerFactory(config).getScheduler();\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/SerializationTestSupport.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\n\n\n\n/**\n * Base class for unit tests that wish to verify backwards compatibility of serialization with earlier versions\n * of Quartz.\n * \n * <p>The way to properly setup tests for subclass is it needs to generate a <ClassName>.ser\n * resource file under the same package. This \".ser\" file only needs to be generated one time,\n * using the version of Quartz matching to the VERSION values. Then during test, each of this\n * file will be deserialized to verify the data.</p>\n */\npublic abstract class SerializationTestSupport  {\n\n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    protected abstract Object getTargetObject() throws Exception;\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    protected abstract String[] getVersions();\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    protected abstract void verifyMatch(Object target, Object deserialized);\n    \n    /**\n     * Test that we can successfully deserialize our target\n     * class for all of the given Quartz versions. \n     */\n    void testSerialization() throws Exception {\n        Object targetObject = getTargetObject();\n        \n        for (int i = 0; i < getVersions().length; i++) {\n            String version = getVersions()[i];\n            \n            verifyMatch(\n                targetObject,\n                deserialize(version, targetObject.getClass()));\n        }\n    }\n    \n    /**\n     * Deserialize the target object from disk.\n     */\n    protected Object deserialize(String version, Class<?> clazz) throws Exception {\n        InputStream is = getClass().getResourceAsStream(getSerializedFileName(version, clazz));\n        \n        ObjectInputStream ois = new ObjectInputStream(is);\n        \n        Object obj = (Object)ois.readObject();\n\n        ois.close();\n        is.close();\n\n        return obj;\n    }\n    \n    /**\n     * Use this method in the future to generate other versions of\n     * of the serialized object file.\n     */\n    public void writeJobDataFile(String version) throws Exception {\n        Object obj = getTargetObject();\n        \n        FileOutputStream fos = new FileOutputStream(getSerializedFileName(version, obj.getClass()));\n        \n        ObjectOutputStream oos = new ObjectOutputStream(fos);\n        \n        oos.writeObject(obj);\n\n        oos.flush();\n        fos.close();\n        oos.close();\n    }\n    \n    /**\n     * Generate the expected name of the serialized object file.\n     */\n    private String getSerializedFileName(String version, Class<?> clazz) {\n        String className = clazz.getName();\n        int index = className.lastIndexOf(\".\");\n        index = (index < 0) ? 0 : index + 1;\n        \n        return className.substring(index) + \"-\" + version + \".ser\";\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/SimpleTriggerTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n\n/**\n * Unit test for SimpleTrigger serialization backwards compatibility.\n */\npublic class SimpleTriggerTest extends SerializationTestSupport {\n    private static final String[] VERSIONS = new String[] {\"2.0\"};\n\n    private static final TimeZone EST_TIME_ZONE = TimeZone.getTimeZone(\"US/Eastern\"); \n    private static final Calendar START_TIME = Calendar.getInstance();\n    private static final Calendar END_TIME = Calendar.getInstance();\n    \n    static\n    {\n        START_TIME.clear();\n        START_TIME.set(2006, Calendar.JUNE, 1, 10, 5, 15);\n        START_TIME.setTimeZone(EST_TIME_ZONE);\n        END_TIME.clear();\n        END_TIME.set(2008, Calendar.MAY, 2, 20, 15, 30);\n        END_TIME.setTimeZone(EST_TIME_ZONE);\n    }\n    \n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    protected Object getTargetObject() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"A\", \"B\");\n        \n        SimpleTriggerImpl t = new SimpleTriggerImpl(\"SimpleTrigger\", \"SimpleGroup\",\n                \"JobName\", \"JobGroup\", START_TIME.getTime(),\n                END_TIME.getTime(), 5, 1000);\n        t.setCalendarName(\"MyCalendar\");\n        t.setDescription(\"SimpleTriggerDesc\");\n        t.setJobDataMap(jobDataMap);\n        t.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);\n\n        return t;\n    }\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        SimpleTriggerImpl targetSimpleTrigger = (SimpleTriggerImpl)target;\n        SimpleTriggerImpl deserializedSimpleTrigger = (SimpleTriggerImpl)deserialized;\n        \n        assertNotNull(deserializedSimpleTrigger);\n        assertEquals(targetSimpleTrigger.getName(), deserializedSimpleTrigger.getName());\n        assertEquals(targetSimpleTrigger.getGroup(), deserializedSimpleTrigger.getGroup());\n        assertEquals(targetSimpleTrigger.getJobName(), deserializedSimpleTrigger.getJobName());\n        assertEquals(targetSimpleTrigger.getJobGroup(), deserializedSimpleTrigger.getJobGroup());\n        assertEquals(targetSimpleTrigger.getStartTime(), deserializedSimpleTrigger.getStartTime());\n        assertEquals(targetSimpleTrigger.getEndTime(), deserializedSimpleTrigger.getEndTime());\n        assertEquals(targetSimpleTrigger.getRepeatCount(), deserializedSimpleTrigger.getRepeatCount());\n        assertEquals(targetSimpleTrigger.getRepeatInterval(), deserializedSimpleTrigger.getRepeatInterval());\n        assertEquals(targetSimpleTrigger.getCalendarName(), deserializedSimpleTrigger.getCalendarName());\n        assertEquals(targetSimpleTrigger.getDescription(), deserializedSimpleTrigger.getDescription());\n        assertEquals(targetSimpleTrigger.getJobDataMap(), deserializedSimpleTrigger.getJobDataMap());\n        assertEquals(targetSimpleTrigger.getMisfireInstruction(), deserializedSimpleTrigger.getMisfireInstruction());\n    }\n    @Test\n    void testUpdateAfterMisfire() {\n        \n        Calendar startTime = Calendar.getInstance();\n        startTime.set(2005, Calendar.JULY, 5, 9, 0, 0);\n        \n        Calendar endTime = Calendar.getInstance();\n        endTime.set(2005, Calendar.JULY, 5, 10, 0, 0);\n        \n        SimpleTriggerImpl simpleTrigger = new SimpleTriggerImpl();\n        simpleTrigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT);\n        simpleTrigger.setRepeatCount(5);\n        simpleTrigger.setStartTime(startTime.getTime());\n        simpleTrigger.setEndTime(endTime.getTime());\n        \n        simpleTrigger.updateAfterMisfire(null);\n        assertEquals(startTime.getTime(), simpleTrigger.getStartTime());\n        assertEquals(endTime.getTime(), simpleTrigger.getEndTime());\n        assertNull(simpleTrigger.getNextFireTime());\n    }\n    @Test\n    void testGetFireTimeAfter() {\n        SimpleTriggerImpl simpleTrigger = new SimpleTriggerImpl();\n\n        simpleTrigger.setStartTime(new Date(0));\n        simpleTrigger.setRepeatInterval(10);\n        simpleTrigger.setRepeatCount(4);\n        \n        Date fireTimeAfter = simpleTrigger.getFireTimeAfter(new Date(34));\n        assertEquals(40, fireTimeAfter.getTime());\n    }\n    @Test\n    void testClone() {\n        SimpleTriggerImpl simpleTrigger = new SimpleTriggerImpl();\n        \n        // Make sure empty sub-objects are cloned okay\n        Trigger clone = (Trigger)simpleTrigger.clone();\n        assertEquals(0, clone.getJobDataMap().size());\n        \n        // Make sure non-empty sub-objects are cloned okay\n        simpleTrigger.getJobDataMap().put(\"K1\", \"V1\");\n        simpleTrigger.getJobDataMap().put(\"K2\", \"V2\");\n        clone = (Trigger)simpleTrigger.clone();\n        assertEquals(2, clone.getJobDataMap().size());\n        assertEquals(\"V1\", clone.getJobDataMap().get(\"K1\"));\n        assertEquals(\"V2\", clone.getJobDataMap().get(\"K2\"));\n        \n        // Make sure sub-object collections have really been cloned by ensuring \n        // their modification does not change the source Trigger \n        clone.getJobDataMap().remove(\"K1\");\n        assertEquals(1, clone.getJobDataMap().size());\n        \n        assertEquals(2, simpleTrigger.getJobDataMap().size());\n        assertEquals(\"V1\", simpleTrigger.getJobDataMap().get(\"K1\"));\n        assertEquals(\"V2\", simpleTrigger.getJobDataMap().get(\"K2\"));\n    }\n    \n    // NPE in equals()\n    @Test\n    void testQuartz665() {\n        new SimpleTriggerImpl().equals(new SimpleTriggerImpl());\n    }\n\n    @Test\n    void testMisfireInstructionValidity() {\n        SimpleTriggerImpl trigger = new SimpleTriggerImpl();\n\n        try {\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);\n            trigger.setMisfireInstruction(Trigger.MISFIRE_INSTRUCTION_SMART_POLICY);\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT);\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT);\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT);\n        }\n        catch(Exception e) {\n            fail(\"Unexpected exception while setting misfire instruction: \" + e.getMessage());\n        }\n        \n        try {\n            trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT + 1);\n            \n            fail(\"Expected exception while setting invalid misfire instruction but did not get it.\");\n        }\n        catch(Exception e) {\n        }\n    }\n\n    \n    // execute with version number to generate a new version's serialized form\n    public static void main(String[] args) throws Exception {\n        new SimpleTriggerTest().writeJobDataFile(\"2.0\");\n    }\n    \n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/TriggerBuilderTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.quartz.DateBuilder.evenSecondDateAfterNow;\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.time.Instant;\nimport java.util.Date;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DateBuilder.IntervalUnit;\n\n/**\n * Test TriggerBuilder functionality\n */\npublic class TriggerBuilderTest  {\n\n\n    @SuppressWarnings(\"deprecation\")\n    public static class TestStatefulJob implements StatefulJob {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n\n    public static class TestJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n    \n    @DisallowConcurrentExecution\n    @PersistJobDataAfterExecution\n    public static class TestAnnotatedJob implements Job {\n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n        }\n    }\n\n/*    @Override\n    protected void setUp() throws Exception {\n    }*/\n    @Test\n    void testTriggerBuilder() {\n        \n        Trigger trigger = newTrigger()\n            .build();\n\n        assertNotNull(trigger.getKey().getName(), \"Expected non-null trigger name \");\n        assertEquals(JobKey.DEFAULT_GROUP, trigger.getKey().getGroup(), \"Unexpected trigger group: \" + trigger.getKey().getGroup());\n        assertNull(trigger.getJobKey(), \"Unexpected job key: \" + trigger.getJobKey());\n        assertNull(trigger.getDescription(), \"Unexpected job description: \" + trigger.getDescription());\n        assertEquals(Trigger.DEFAULT_PRIORITY, trigger.getPriority(), \"Unexpected trigger priority: \" + trigger.getPriority());\n        assertNotNull(trigger.getStartTime(), \"Unexpected start-time: \" + trigger.getStartTime());\n        assertNull(trigger.getEndTime(), \"Unexpected end-time: \" + trigger.getEndTime());\n        \n        Date stime = evenSecondDateAfterNow();\n        \n        trigger = newTrigger()\n            .withIdentity(\"t1\")\n            .withDescription(\"my description\")\n            .withPriority(2)\n            .endAt(futureDate(10, IntervalUnit.WEEK))\n            .startAt(stime)\n            .build();\n\n        assertEquals(\"t1\", trigger.getKey().getName(), \"Unexpected trigger name \" + trigger.getKey().getName());\n        assertEquals(JobKey.DEFAULT_GROUP, trigger.getKey().getGroup(), \"Unexpected trigger group: \" + trigger.getKey().getGroup());\n        assertNull(trigger.getJobKey(), \"Unexpected job key: \" + trigger.getJobKey());\n        assertEquals(\"my description\", trigger.getDescription(), \"Unexpected job description: \" + trigger.getDescription());\n        assertEquals(2, trigger.getPriority(), \"Unexpected trigger priority: \" + trigger);\n        assertEquals(trigger.getStartTime(), stime, \"Unexpected start-time: \" + trigger.getStartTime());\n        assertNotNull(trigger.getEndTime(), \"Unexpected end-time: \" + trigger.getEndTime());\n        \n    }\n    \n    /** QTZ-157 */\n    @Test\n    void testTriggerBuilderWithEndTimePriorCurrentTime() throws Exception {\n    \tTriggerBuilder.newTrigger()\n                .withIdentity(\"some trigger name\", \"some trigger group\")\n                .forJob(\"some job name\", \"some job group\")\n                .startAt(new Date(System.currentTimeMillis() - 200000000))\n                .endAt(new Date(System.currentTimeMillis() - 100000000))\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"0 0 0 * * ?\"))\n                .build();\n    }\n\n    @Test\n    void testTriggerBuilderWithInstant() throws InterruptedException {\n        Instant instantTime = Instant.now().plusSeconds(3L);\n        Trigger trigger = TriggerBuilder.newTrigger()\n                .withIdentity(\"triggerTest Instant\", \"triggerTest Instant group\")\n                .forJob(\"test job Instant\", \"test job Instant group\")\n                .startAt(instantTime)\n                .build();\n        assertEquals(Date.from(instantTime), trigger.getStartTime());\n        Thread.sleep(5000);\n        assertEquals(Date.from(instantTime), trigger.getFinalFireTime());\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/TriggerComparatorTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.quartz.DateBuilder.futureDate;\nimport static org.quartz.DateBuilder.IntervalUnit.MINUTE;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.spi.OperableTrigger;\n\nclass TriggerComparatorTest  {\n\n    @Test\n    void testTriggerSort() {\n        \n        // build trigger in expected sort order\n        Trigger t1 = newTrigger().withIdentity(\"a\").build();\n        Trigger t2 = newTrigger().withIdentity(\"b\").build();\n        Trigger t3 = newTrigger().withIdentity(\"c\").build();\n        Trigger t4 = newTrigger().withIdentity(\"a\", \"a\").build();\n        Trigger t5 = newTrigger().withIdentity(\"a\", \"b\").build();\n        Trigger t6 = newTrigger().withIdentity(\"a\", \"c\").build();\n\n        List<Trigger> ts = new LinkedList<Trigger>();\n        // add triggers to list in somewhat randomized order\n        ts.add(t5);\n        ts.add(t6);\n        ts.add(t4);\n        ts.add(t3);\n        ts.add(t1);\n        ts.add(t2);\n\n        // sort the list\n        Collections.sort(ts);\n        \n        // check the order of the list\n        assertEquals(t1, ts.get(0));\n        assertEquals(t2, ts.get(1));\n        assertEquals(t3, ts.get(2));\n        assertEquals(t4, ts.get(3));\n        assertEquals(t5, ts.get(4));\n        assertEquals(t6, ts.get(5));\n    }\n\n    @Test\n    void testTriggerTimeSort() {\n        \n        \n        // build trigger in expected sort order\n        Trigger t1 = newTrigger().withIdentity(\"a\").startAt(futureDate(1, MINUTE)).build();\n        ((OperableTrigger)t1).computeFirstFireTime(null);\n        Trigger t2 = newTrigger().withIdentity(\"b\").startAt(futureDate(2, MINUTE)).build();\n        ((OperableTrigger)t2).computeFirstFireTime(null);\n        Trigger t3 = newTrigger().withIdentity(\"c\").startAt(futureDate(3, MINUTE)).build();\n        ((OperableTrigger)t3).computeFirstFireTime(null);\n        Trigger t4 = newTrigger().withIdentity(\"d\").startAt(futureDate(5, MINUTE)).withPriority(7).build();\n        ((OperableTrigger)t4).computeFirstFireTime(null);\n        Trigger t5 = newTrigger().withIdentity(\"e\").startAt(futureDate(5, MINUTE)).build();\n        ((OperableTrigger)t5).computeFirstFireTime(null);\n        Trigger t6 = newTrigger().withIdentity(\"g\").startAt(futureDate(5, MINUTE)).build();\n        ((OperableTrigger)t6).computeFirstFireTime(null);\n        Trigger t7 = newTrigger().withIdentity(\"h\").startAt(futureDate(5, MINUTE)).withPriority(2).build();\n        ((OperableTrigger)t7).computeFirstFireTime(null);\n        Trigger t8 = newTrigger().withIdentity(\"i\").startAt(futureDate(6, MINUTE)).build();\n        ((OperableTrigger)t8).computeFirstFireTime(null);\n        Trigger t9 = newTrigger().withIdentity(\"j\").startAt(futureDate(7, MINUTE)).build();\n        ((OperableTrigger)t9).computeFirstFireTime(null);\n\n        List<Trigger> ts = new LinkedList<Trigger>();\n        // add triggers to list in somewhat randomized order\n        ts.add(t5);\n        ts.add(t9);\n        ts.add(t6);\n        ts.add(t8);\n        ts.add(t4);\n        ts.add(t3);\n        ts.add(t1);\n        ts.add(t7);\n        ts.add(t2);\n        \n        // sort the list\n        Collections.sort(ts);\n        \n        // check the order of the list\n        assertEquals(t1, ts.get(0));\n        assertEquals(t2, ts.get(1));\n        assertEquals(t3, ts.get(2));\n        assertEquals(t4, ts.get(3));\n        assertEquals(t5, ts.get(4));\n        assertEquals(t6, ts.get(5));\n        assertEquals(t7, ts.get(6));\n        assertEquals(t8, ts.get(7));\n        assertEquals(t9, ts.get(8));\n    }\n\n}\n\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/VersionTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz;\n\nimport java.util.regex.Pattern;\nimport java.util.regex.Matcher;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.core.QuartzScheduler;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass VersionTest  {\n    @SuppressWarnings(\"unused\")\n    private static final String SNAPSHOT_SUFFIX = \"-SNAPSHOT\";\n    @SuppressWarnings(\"unused\")\n    private static final String PROTOTYPE_SUFFIX = \"-PROTO\";\n\n    @Test\n    void testVersionParsing() {\n        assertNonNegativeInteger(QuartzScheduler.getVersionMajor());\n        assertNonNegativeInteger(QuartzScheduler.getVersionMinor());\n\n        String iter = QuartzScheduler.getVersionIteration();\n        assertNotNull(iter);\n        Pattern suffix = Pattern.compile(\"(\\\\d+)(-\\\\w+)?\");\n        Matcher m = suffix.matcher(iter);\n        if (m.matches()) {\n          assertNonNegativeInteger(m.group(1));\n        } else {\n          throw new RuntimeException(iter + \" doesn't match pattern '(\\\\d+)(-\\\\w+)?'\");\n        } \n\n    }\n\n    private void assertNonNegativeInteger(String s) {\n        assertNotNull(s);\n        boolean parsed = false;\n        int intVal = -1;\n        try {\n            intVal = Integer.parseInt(s);\n            parsed = true;\n        } catch (NumberFormatException e) {}\n\n        assertTrue(parsed, \"Failed parse version segment: \" + s);\n        assertTrue(intVal >= 0);\n    }\n}\n\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/core/ListenerManagerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.core;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.quartz.impl.matchers.GroupMatcher.jobGroupEquals;\nimport static org.quartz.impl.matchers.GroupMatcher.triggerGroupEquals;\nimport static org.quartz.impl.matchers.NameMatcher.jobNameContains;\n\nimport java.util.List;\nimport java.util.UUID;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobListener;\nimport org.quartz.SchedulerListener;\nimport org.quartz.TriggerKey;\nimport org.quartz.TriggerListener;\nimport org.quartz.impl.matchers.NameMatcher;\nimport org.quartz.listeners.JobListenerSupport;\nimport org.quartz.listeners.SchedulerListenerSupport;\nimport org.quartz.listeners.TriggerListenerSupport;\n\n/**\n * Test ListenerManagerImpl functionality \n */\nclass ListenerManagerTest  {\n\n\n    public static class TestJobListener extends JobListenerSupport {\n\n        private String name;\n        \n        public TestJobListener(String name) {\n            this.name = name;\n        }\n        \n        public String getName() {\n            return name;\n        }\n    }\n\n    public static class TestTriggerListener extends TriggerListenerSupport {\n\n        private String name;\n        \n        public TestTriggerListener(String name) {\n            this.name = name;\n        }\n        \n        public String getName() {\n            return name;\n        }\n    }\n\n    public static class TestSchedulerListener extends SchedulerListenerSupport {\n\n    }\n\n\n\n    @Test\n    void testManagementOfJobListeners() throws Exception {\n\n        JobListener tl1 = new TestJobListener(\"tl1\");\n        JobListener tl2 = new TestJobListener(\"tl2\");\n\n        ListenerManagerImpl manager = new ListenerManagerImpl();\n\n        // test adding listener without matcher\n        manager.addJobListener(tl1);\n        assertEquals(1, manager.getJobListeners().size(), \"Unexpected size of listener list\");\n\n        // test adding listener with matcher\n        manager.addJobListener(tl2, jobGroupEquals(\"foo\"));\n        assertEquals(2, manager.getJobListeners().size(), \"Unexpected size of listener list\");\n\n        // test removing a listener\n        manager.removeJobListener(\"tl1\");\n        assertEquals(1, manager.getJobListeners().size(), \"Unexpected size of listener list\");\n\n        // test adding a matcher\n        manager.addJobListenerMatcher(\"tl2\", jobNameContains(\"foo\"));\n        assertEquals(2, manager.getJobListenerMatchers(\"tl2\").size(), \"Unexpected size of listener's matcher list\");\n\n        // Test ordering of registration is preserved.\n        final int numListenersToTestOrderOf = 15;\n        manager = new ListenerManagerImpl();\n        JobListener[] listeners = new JobListener[numListenersToTestOrderOf];\n        for(int i = 0; i < numListenersToTestOrderOf; i++) {\n            // use random name, to help test that order isn't based on naming or coincidental hashing\n            listeners[i] = new TestJobListener(UUID.randomUUID().toString());\n            manager.addJobListener(listeners[i]);\n        }\n        List<JobListener> mls = manager.getJobListeners();\n        int i = 0;\n        for(JobListener listener: mls) {\n            assertSame(listeners[i], listener, \"Unexpected order of listeners\");\n            i++;\n        }\n    }\n    @Test\n    void testManagementOfTriggerListeners() throws Exception {\n\n        TriggerListener tl1 = new TestTriggerListener(\"tl1\");\n        TriggerListener tl2 = new TestTriggerListener(\"tl2\");\n\n        ListenerManagerImpl manager = new ListenerManagerImpl();\n\n        // test adding listener without matcher\n        manager.addTriggerListener(tl1);\n        assertEquals(1, manager.getTriggerListeners().size(), \"Unexpected size of listener list\");\n\n        // test adding listener with matcher\n        manager.addTriggerListener(tl2, triggerGroupEquals(\"foo\"));\n        assertEquals(2, manager.getTriggerListeners().size(), \"Unexpected size of listener list\");\n\n        // test removing a listener\n        manager.removeTriggerListener(\"tl1\");\n        assertEquals(1, manager.getTriggerListeners().size(), \"Unexpected size of listener list\");\n\n        // test adding a matcher\n        manager.addTriggerListenerMatcher(\"tl2\", NameMatcher.<TriggerKey>nameContains(\"foo\"));\n        assertEquals(2, manager.getTriggerListenerMatchers(\"tl2\").size(), \"Unexpected size of listener's matcher list\");\n\n        // Test ordering of registration is preserved.\n        final int numListenersToTestOrderOf = 15;\n        manager = new ListenerManagerImpl();\n        TriggerListener[] listeners = new TriggerListener[numListenersToTestOrderOf];\n        for(int i = 0; i < numListenersToTestOrderOf; i++) {\n            // use random name, to help test that order isn't based on naming or coincidental hashing\n            listeners[i] = new TestTriggerListener(UUID.randomUUID().toString());\n            manager.addTriggerListener(listeners[i]);\n        }\n        List<TriggerListener> mls = manager.getTriggerListeners();\n        int i = 0;\n        for(TriggerListener listener: mls) {\n            assertSame(listeners[i], listener, \"Unexpected order of listeners\");\n            i++;\n        }\n    }\n\n    @Test\n    void testManagementOfSchedulerListeners() throws Exception {\n\n        SchedulerListener tl1 = new TestSchedulerListener();\n        SchedulerListener tl2 = new TestSchedulerListener();\n\n        ListenerManagerImpl manager = new ListenerManagerImpl();\n\n        // test adding listener without matcher\n        manager.addSchedulerListener(tl1);\n        assertEquals(1, manager.getSchedulerListeners().size(), \"Unexpected size of listener list\");\n\n        // test adding listener with matcher\n        manager.addSchedulerListener(tl2);\n        assertEquals(2, manager.getSchedulerListeners().size(), \"Unexpected size of listener list\");\n\n        // test removing a listener\n        manager.removeSchedulerListener(tl1);\n        assertEquals(1, manager.getSchedulerListeners().size(), \"Unexpected size of listener list\");\n\n        // Test ordering of registration is preserved.\n        final int numListenersToTestOrderOf = 15;\n        manager = new ListenerManagerImpl();\n        SchedulerListener[] listeners = new SchedulerListener[numListenersToTestOrderOf];\n        for (int i = 0; i < numListenersToTestOrderOf; i++) {\n            listeners[i] = new TestSchedulerListener();\n            manager.addSchedulerListener(listeners[i]);\n        }\n        List<SchedulerListener> mls = manager.getSchedulerListeners();\n        int i = 0;\n        for (SchedulerListener listener : mls) {\n            assertSame(listeners[i], listener, \"Unexpected order of listeners\");\n            i++;\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/core/QTZ212_SchedulerListener_Test.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.core;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SchedulerListener;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.listeners.BroadcastSchedulerListener;\nimport org.quartz.listeners.SchedulerListenerSupport;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Test that verifies that schedulerStarting() is called before the schedulerStarted()\n *  \n * \n * @author adahanne\n *\n */\nclass QTZ212_SchedulerListener_Test {\n\n\tprivate static final String SCHEDULER_STARTED = \"SCHEDULER_STARTED\";\n\tprivate static final String SCHEDULER_STARTING = \"SCHEDULER_STARTING\";\n\tprivate static List<String> methodsCalledInSchedulerListener =  new ArrayList<String>();\n\t\n\t\n\t@Test\n\tvoid stdSchedulerCallsStartingBeforeStartedTest() throws SchedulerException {\n\t\tSchedulerFactory sf = new StdSchedulerFactory();\n\t\tScheduler sched = sf.getScheduler();\n\t\tsched.getListenerManager().addSchedulerListener(new TestSchedulerListener());\n\t\tsched.start();\n\t\t\n\t\tassertEquals(SCHEDULER_STARTING,methodsCalledInSchedulerListener.get(0));\n\t\tassertEquals(SCHEDULER_STARTED,methodsCalledInSchedulerListener.get(1));\n\t\t\n\t\tsched.shutdown();\n\t}\n\t\n\t\n\t@Test\n\tvoid broadcastSchedulerListenerCallsSchedulerStartingOnAllItsListeners() throws SchedulerException {\n\t\t\n\t\tmethodsCalledInSchedulerListener =  new ArrayList<String>();\n\t\tSchedulerFactory sf = new StdSchedulerFactory();\n\t\tScheduler sched = sf.getScheduler();\n\t\tList<SchedulerListener> listeners=  new ArrayList<SchedulerListener>();\n\t\tlisteners.add(new TestSchedulerListener());\n\t\t\n\t\tsched.getListenerManager().addSchedulerListener(new BroadcastSchedulerListener(listeners));\n\t\tsched.start();\n\t\t\n\t\tassertEquals(SCHEDULER_STARTING,methodsCalledInSchedulerListener.get(0));\n\t\tassertEquals(SCHEDULER_STARTED,methodsCalledInSchedulerListener.get(1));\n\t\t\n\t\tsched.shutdown();\n\t}\n\n\tpublic static class TestSchedulerListener extends SchedulerListenerSupport {\n\n\t\t@Override\n\t\tpublic void schedulerStarted() {\n\t\t\tmethodsCalledInSchedulerListener.add(SCHEDULER_STARTED);\n\t\t\tSystem.out.println(\"schedulerStarted was called\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void schedulerStarting() {\n\t\t\tmethodsCalledInSchedulerListener.add(SCHEDULER_STARTING);\n\t\t\tSystem.out.println(\"schedulerStarting was called\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/core/QTZ385Test.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.core;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JobStoreTX;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.integrations.tests.HelloJob;\nimport org.quartz.listeners.JobListenerSupport;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.JobStore;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\n/**\n *\n * @author cdennis\n */\nclass QTZ385Test {\n  \n  private static final Method TRIGGERS_FIRED;\n  static {\n    try {\n      TRIGGERS_FIRED = JobStore.class.getDeclaredMethod(\"triggersFired\", new Class[] {List.class});\n    } catch (NoSuchMethodException e) {\n      throw new AssertionError(e);\n    }\n  }\n\n  @Test\n  void testShutdownOrdering() throws SchedulerException, SQLException, InterruptedException, BrokenBarrierException {\n    JdbcQuartzTestUtilities.createDatabase(\"testShutdownOrdering\", DatabaseType.DERBY);\n    try {\n      final CyclicBarrier barrier = new CyclicBarrier(2);\n      final JobStoreTX realJobStore = new JobStoreTX();\n      realJobStore.setDataSource(\"testShutdownOrdering\");\n      realJobStore.setInstanceId(\"SINGLE_NODE_TEST\");\n      realJobStore.setInstanceName(\"testShutdownOrdering\");\n\n      JobStore evilJobStore = (JobStore) Proxy.newProxyInstance(JobStore.class.getClassLoader(), new Class[] {JobStore.class}, new InvocationHandler() {\n        @Override\n        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n          if (TRIGGERS_FIRED.equals(method)) {\n            Object result = method.invoke(realJobStore, args);\n            barrier.await();\n            try {\n              barrier.await(1, TimeUnit.SECONDS);\n            } catch (Exception e) {\n              //ignore\n            }\n            return result;\n          } else {\n            return method.invoke(realJobStore, args);\n          }\n        }\n      });\n\n      DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();\n      factory.createScheduler(new SimpleThreadPool(1, Thread.NORM_PRIORITY), evilJobStore);\n      Scheduler scheduler = factory.getScheduler();\n      try {\n        scheduler.scheduleJob(JobBuilder.newJob(HelloJob.class).withIdentity(\"test\").requestRecovery().build(), \n                TriggerBuilder.newTrigger().withIdentity(\"test\").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(1)).build());\n        scheduler.start();\n        barrier.await();\n      } finally {\n        scheduler.shutdown(true);\n      }\n\n      try {\n        barrier.await(1, TimeUnit.SECONDS);\n      } catch (Exception e) {\n        //ignore\n      }\n      \n      \n      final AtomicBoolean recoveredJob = new AtomicBoolean(false);\n      factory.createScheduler(new SimpleThreadPool(1, Thread.NORM_PRIORITY), realJobStore);\n      Scheduler recovery = factory.getScheduler();\n      try {\n        recovery.getListenerManager().addJobListener(new JobListenerSupport() {\n\n          @Override\n          public String getName() {\n            return QTZ385Test.class.getSimpleName();\n          }\n\n          @Override\n          public void jobToBeExecuted(JobExecutionContext context) {\n            if (context.isRecovering()) {\n              recoveredJob.set(true);\n            }\n          }\n        });\n        recovery.start();\n        Thread.sleep(1000);\n        assertFalse(recoveredJob.get());\n      } finally {\n        recovery.shutdown(true);\n      }\n    } finally {\n        JdbcQuartzTestUtilities.destroyDatabase(\"testShutdownOrdering\", DatabaseType.DERBY);\n    }\n  }\n  \n  \n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/core/RecoverJobsTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.core;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JobStoreTX;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.*;\nimport org.quartz.listeners.JobListenerSupport;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.utils.DBConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * @author https://github.com/eugene-goroschenya\n */\npublic class RecoverJobsTest {\n\n    @Test\n    void testRecoveringRepeatJobWhichIsFiredAndMisfiredAtTheSameTime() throws SchedulerException, SQLException, InterruptedException {\n        String dsName = \"recoverJobsTest\";\n        JdbcQuartzTestUtilities.createDatabase(dsName, DatabaseType.DERBY);\n        try {\n            final JobStoreTX jobStore = new JobStoreTX();\n            jobStore.setDataSource(dsName);\n            jobStore.setInstanceId(\"SINGLE_NODE_TEST\");\n            jobStore.setInstanceName(dsName);\n            jobStore.setMisfireThreshold(1000);\n\n            DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();\n\n            factory.createScheduler(new SimpleThreadPool(1, Thread.NORM_PRIORITY), jobStore);\n            Scheduler scheduler = factory.getScheduler();\n\n            // run forever up to the first fail over situation\n            RecoverJobsTestJob.runForever = true;\n\n            scheduler.scheduleJob(\n                    JobBuilder.newJob(RecoverJobsTestJob.class)\n                            .withIdentity(\"test\")\n                            .build(),\n                    TriggerBuilder.newTrigger()\n                            .withIdentity(\"test\")\n                            .withSchedule(\n                                    SimpleScheduleBuilder.simpleSchedule()\n                                            .withIntervalInMilliseconds(1000)\n                                            .repeatForever()\n                            ).build()\n            );\n\n            scheduler.start();\n\n            // wait to be sure job is executing\n            Thread.sleep(2000);\n\n            // emulate fail over situation\n            scheduler.shutdown(false);\n\n            Connection conn = DBConnectionManager.getInstance().getConnection(dsName);\n            try {\n                Statement st = conn.createStatement();\n                ResultSet rs1 = st.executeQuery(\"SELECT TRIGGER_STATE from QRTZ_TRIGGERS\");\n                rs1.next();\n                // check that trigger is blocked after fail over situation\n                assertEquals(\"BLOCKED\", rs1.getString(1));\n\n                ResultSet rs2 = st.executeQuery(\"SELECT count(*) from QRTZ_FIRED_TRIGGERS\");\n                rs2.next();\n                // check that fired trigger remains after fail over situation\n                assertEquals(1, rs2.getLong(1));\n                st.close();\n            } finally {\n                conn.close();\n            }\n\n            // stop job executing to not as part of emulation fail over situation\n            RecoverJobsTestJob.runForever = false;\n\n            // emulate down time >> trigger interval - misfireThreshold\n            Thread.sleep(4000);\n\n            final AtomicBoolean isJobRecovered = new AtomicBoolean(false);\n            factory.createScheduler(new SimpleThreadPool(1, Thread.NORM_PRIORITY), jobStore);\n            Scheduler recovery = factory.getScheduler();\n            recovery.getListenerManager().addJobListener(new JobListenerSupport() {\n                @Override\n                public String getName() {\n                    return RecoverJobsTest.class.getSimpleName();\n                }\n\n                @Override\n                public void jobToBeExecuted(JobExecutionContext context) {\n                    isJobRecovered.set(true);\n                }\n            });\n            recovery.start();\n\n            // wait to be sure recovered job was executed\n            Thread.sleep(2000);\n\n            // wait job\n            recovery.shutdown(true);\n\n           assertTrue(isJobRecovered.get());\n        } finally {\n            JdbcQuartzTestUtilities.destroyDatabase(dsName, DatabaseType.DERBY);\n        }\n    }\n\n    /**\n     * @author https://github.com/eugene-goroschenya\n     */\n    @DisallowConcurrentExecution\n    public static class RecoverJobsTestJob implements Job {\n        private static Logger _log = LoggerFactory.getLogger(RecoverJobsTestJob.class);\n        static boolean runForever = true;\n\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            long now = System.currentTimeMillis();\n            int tic = 0;\n            _log.info(\"Started - \" + now);\n            try {\n                while (runForever) {\n                    Thread.sleep(1000);\n                    _log.info(\"Tic \" + (++tic) + \"- \" + now);\n                }\n                _log.info(\"Stopped - \" + now);\n            } catch (InterruptedException e) {\n                _log.info(\"Interrupted - \" + now);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/DirectSchedulerFactoryTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.impl;\n\nimport java.lang.reflect.Field;\nimport java.util.Collections;\nimport java.util.List;\n\n\n\nimport org.quartz.Scheduler;\nimport org.quartz.core.QuartzScheduler;\nimport org.quartz.core.QuartzSchedulerResources;\nimport org.quartz.simpl.RAMJobStore;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\nimport org.quartz.spi.ThreadPool;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\npublic class DirectSchedulerFactoryTest  {\n    void testPlugins() throws Exception {\n        final StringBuffer result = new StringBuffer();\n        \n        SchedulerPlugin testPlugin = new SchedulerPlugin() {\n            public void initialize(String name, org.quartz.Scheduler scheduler, ClassLoadHelper classLoadHelper) throws org.quartz.SchedulerException {\n                result.append(name).append(\"|\").append(scheduler.getSchedulerName());\n            };\n            public void start() {\n                result.append(\"|start\");\n            };\n            public void shutdown() {\n                result.append(\"|shutdown\");\n            };\n        };\n        \n        ThreadPool threadPool = new SimpleThreadPool(1, 5);\n        threadPool.initialize();\n        DirectSchedulerFactory.getInstance().createScheduler(\n                \"MyScheduler\", \"Instance1\", threadPool,\n                new RAMJobStore(), Collections.singletonMap(\"TestPlugin\", testPlugin), \n                null, -1, 0, 0, false, null);\n        \n        Scheduler scheduler = DirectSchedulerFactory.getInstance().getScheduler(\"MyScheduler\");\n        scheduler.start();\n        scheduler.shutdown();\n        \n        assertEquals(\"TestPlugin|MyScheduler|start|shutdown\", result.toString());\n    }\n\n    void testThreadName() throws Throwable {\n        DirectSchedulerFactory.getInstance().createVolatileScheduler(4);\n        Scheduler scheduler = DirectSchedulerFactory.getInstance().getScheduler();\n        QuartzScheduler qs = getField(scheduler, \"sched\");\n        QuartzSchedulerResources qsr = getField(qs, \"resources\");\n        ThreadPool tp = qsr.getThreadPool();\n        List<?> list = getField(tp,\"workers\");\n        Object workerThread = list.get(0);\n        String workerThreadName = workerThread.toString();\n        assertFalse(workerThreadName.contains(\"null\"));\n        assertTrue(workerThreadName.contains(scheduler.getSchedulerName()));\n\n    }\n\n    <T> T getField(Object obj, String fieldName) throws Exception {\n        Field field = obj.getClass().getDeclaredField(fieldName);\n        field.setAccessible(true);\n        return (T)field.get(obj);\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/JobDetailImplTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport org.hamcrest.Matchers;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobDetailImplTest {\n\t@Test\n\tvoid testHashCode() {\n\t\tJobDetailImpl job = new JobDetailImpl();\n\t\tassertThat(job.hashCode(), Matchers.is(0));\n\t\t\n\t\tjob.setName(\"test\");\n\t\tassertThat(job.hashCode(), Matchers.not(Matchers.is(0)));\n\t\t\n\t\tjob.setGroup(\"test\");\n\t\tassertThat(job.hashCode(), Matchers.not(Matchers.is(0)));\n\t}\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/MockConnectionProvider.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.quartz.utils.ConnectionProvider;\n\n/**\n * Mock implementation of a ConnectionProvider\n * that keeps track of the order of it methods calls\n * \n * @author adahanne\n */\npublic class MockConnectionProvider implements ConnectionProvider {\n\n\tprivate String customProperty; \n\tpublic static List<String> methodsCalled = new ArrayList<String>();\n\t\n\tpublic Connection getConnection() throws SQLException {\n\t\tmethodsCalled.add(\"getConnection\");\n\t\tthrow new MockSQLException(\"getConnection correctly called on MockConnectionProvider\");\n\t}\n\n\tpublic void shutdown() throws SQLException {\n\t}\n\n\tpublic void initialize() throws SQLException {\n\t\tmethodsCalled.add(\"initialize\");\n\n\t}\n\n\tpublic void setCustomProperty(String customProperty) {\n\t\tmethodsCalled.add(\"setCustomProperty(\"+customProperty+\")\");\n\t}\n\t\n}\n\nclass MockSQLException extends SQLException{\n\tpublic MockSQLException(String string) {\n\t\tsuper(string);\n\t}\n\t\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/RemoteMBeanSchedulerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerMetaData;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.core.QuartzSchedulerResources;\nimport org.quartz.impl.calendar.BaseCalendar;\nimport org.quartz.impl.matchers.GroupMatcher;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.management.AttributeList;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\n/**\n * RemoteMBeanSchedulerTest\n */\npublic class RemoteMBeanSchedulerTest {\n\n    public static final String TRIGGER_KEY = \"trigger1\";\n    public static final String GROUP_KEY = \"group1\";\n    public static final String JOB_KEY = \"job1\";\n    public static final String CALENDAR_KEY = \"calendar1\";\n\n    private Scheduler scheduler;\n    private RemoteMBeanScheduler remoteScheduler;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        Properties props = new Properties();\n        props.put(\"org.quartz.scheduler.instanceName\", \"TestScheduler\");\n        props.put(\"org.quartz.jobStore.class\", \"org.quartz.simpl.RAMJobStore\");\n        props.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        props.put(\"org.quartz.threadPool.threadCount\", \"1\");\n        props.put(\"org.quartz.scheduler.jmx.export\", \"true\");\n\n        scheduler = new StdSchedulerFactory(props).getScheduler();\n\n        JobDetail jobDetail = newJob(HelloJob.class).withIdentity(JOB_KEY, GROUP_KEY).build();\n        Trigger trigger = newTrigger().withIdentity(TRIGGER_KEY, GROUP_KEY).startAt(new Date()).build();\n\n        scheduler.addCalendar(CALENDAR_KEY, new BaseCalendar(), false, false);\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        String objectName = QuartzSchedulerResources.generateJMXObjectName(scheduler.getSchedulerName(), scheduler.getSchedulerInstanceId());\n        remoteScheduler = new TestRemoteScheduler(objectName);\n    }\n\n    @AfterEach\n    public void tearDown() throws SchedulerException {\n        scheduler.shutdown();\n    }\n\n    @Test\n    void testJMXAttributesAccess() throws Exception {\n        assertThat(remoteScheduler.getCalendarNames(), equalTo(scheduler.getCalendarNames()));\n        assertThat(remoteScheduler.getJobGroupNames(), equalTo(scheduler.getJobGroupNames()));\n        assertThat(remoteScheduler.getPausedTriggerGroups(), equalTo(scheduler.getPausedTriggerGroups()));\n        assertThat(remoteScheduler.getSchedulerInstanceId(), equalTo(scheduler.getSchedulerInstanceId()));\n        assertThat(remoteScheduler.getSchedulerName(), equalTo(scheduler.getSchedulerName()));\n        assertThat(remoteScheduler.getTriggerGroupNames(), equalTo(scheduler.getTriggerGroupNames()));\n    }\n\n    @Test\n    void testSchedulerMetaData() throws Exception {\n        SchedulerMetaData remoteSchedulerMetaData = remoteScheduler.getMetaData();\n        SchedulerMetaData metaData = scheduler.getMetaData();\n        assertThat(remoteSchedulerMetaData.getSchedulerName(), equalTo(metaData.getSchedulerName()));\n        assertThat(remoteSchedulerMetaData.getSchedulerInstanceId(), equalTo(metaData.getSchedulerInstanceId()));\n        assertThat(remoteSchedulerMetaData.isInStandbyMode(), is(metaData.isInStandbyMode()));\n        assertThat(remoteSchedulerMetaData.getSchedulerClass(), equalTo((Class) TestRemoteScheduler.class));\n        assertThat(remoteSchedulerMetaData.isSchedulerRemote(), is(true));\n        assertThat(remoteSchedulerMetaData.isStarted(), is(false)); // information not available through JMX\n        assertThat(remoteSchedulerMetaData.isInStandbyMode(), is(metaData.isInStandbyMode()));\n        assertThat(remoteSchedulerMetaData.isShutdown(), is(metaData.isShutdown()));\n        assertThat(remoteSchedulerMetaData.getRunningSince(), nullValue()); // Information not available through JMX\n        assertThat(remoteSchedulerMetaData.getNumberOfJobsExecuted(), is(metaData.getNumberOfJobsExecuted()));\n        assertThat(remoteSchedulerMetaData.getJobStoreClass(), equalTo((Class) metaData.getJobStoreClass()));\n        assertThat(remoteSchedulerMetaData.isJobStoreSupportsPersistence(), is(false)); // Information not available through JMX\n        assertThat(remoteSchedulerMetaData.isJobStoreClustered(), is(false)); // Information not available through JMX\n        assertThat(remoteSchedulerMetaData.getThreadPoolClass(), equalTo((Class) metaData.getThreadPoolClass()));\n        assertThat(remoteSchedulerMetaData.getThreadPoolSize(), is(metaData.getThreadPoolSize()));\n        assertThat(remoteSchedulerMetaData.getVersion(), equalTo(metaData.getVersion()));\n        assertThat(remoteSchedulerMetaData.getJobStoreClass(), equalTo((Class) metaData.getJobStoreClass()));\n    }\n\n    @Test\n    void testCalendarOperations() throws Exception {\n        try {\n            remoteScheduler.addCalendar(\"testCal\", new BaseCalendar(), true, true);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.getCalendar(\"test\");\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        remoteScheduler.deleteCalendar(CALENDAR_KEY);\n        assertThat(scheduler.getCalendar(CALENDAR_KEY), nullValue());\n    }\n\n    @Test\n    void testTriggerOperations() throws Exception {\n        TriggerKey triggerKey = new TriggerKey(TRIGGER_KEY, GROUP_KEY);\n        GroupMatcher<TriggerKey> groupMatcher = GroupMatcher.triggerGroupEquals(GROUP_KEY);\n\n        try {\n            remoteScheduler.getTrigger(triggerKey);\n            fail(\"Method had a different return type in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.getTriggersOfJob(new JobKey(JOB_KEY, GROUP_KEY));\n            fail(\"Method had a different return type in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.checkExists(triggerKey);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        assertThat(remoteScheduler.getTriggerState(triggerKey), is(scheduler.getTriggerState(triggerKey)));\n\n        try {\n            remoteScheduler.getTriggerKeys(groupMatcher);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        remoteScheduler.pauseTrigger(triggerKey);\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.PAUSED));\n\n        remoteScheduler.resumeTrigger(triggerKey);\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.NORMAL));\n\n        remoteScheduler.pauseTriggers(groupMatcher);\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.PAUSED));\n\n        remoteScheduler.resumeTriggers(groupMatcher);\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.NORMAL));\n\n        remoteScheduler.pauseAll();\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.PAUSED));\n\n        remoteScheduler.resumeAll();\n        assertThat(scheduler.getTriggerState(triggerKey), is(Trigger.TriggerState.NORMAL));\n    }\n\n    @Test\n    void testJobOperations() throws Exception {\n\n        JobKey job2 = new JobKey(\"job2\", GROUP_KEY);\n        JobDetail job2Detail = newJob(HelloJob.class).withIdentity(job2).storeDurably().build();\n\n        remoteScheduler.addJob(job2Detail, false);\n\n        assertThat(remoteScheduler.getJobDetail(job2), equalTo(job2Detail));\n\n        try {\n            remoteScheduler.checkExists(job2);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n\n        remoteScheduler.pauseJob(job2);\n        remoteScheduler.resumeJob(job2);\n\n        GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals(GROUP_KEY);\n        remoteScheduler.pauseJobs(matcher);\n        remoteScheduler.resumeJobs(matcher);\n\n        assertThat(remoteScheduler.getJobKeys(matcher).size(), is(2));\n\n        assertThat(remoteScheduler.interrupt(job2), is(false));\n\n        try {\n            remoteScheduler.triggerJob(job2);\n            fail(\"Method had different parameters in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.scheduleJob(null, null);\n            fail(\"Method had different parameters in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.scheduleJob(null);\n            fail(\"Method had different parameters in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.scheduleJobs(null, false);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        assertThat(remoteScheduler.unscheduleJob(TriggerKey.triggerKey(TRIGGER_KEY, GROUP_KEY)), is(true));\n\n        try {\n            remoteScheduler.unscheduleJobs(null);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.rescheduleJob(null, null);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        assertThat(remoteScheduler.deleteJob(job2), is(true));\n\n        try {\n            remoteScheduler.deleteJobs(Collections.singletonList(JobKey.jobKey(JOB_KEY, GROUP_KEY)));\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n    }\n\n    @Test\n    void testLifecycleOperations() throws SchedulerException {\n        try {\n            remoteScheduler.startDelayed(60);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        remoteScheduler.start();\n        assertThat(remoteScheduler.isStarted(), is(true));\n        assertThat(scheduler.isStarted(), is(true));\n\n        remoteScheduler.standby();\n        assertThat(remoteScheduler.isInStandbyMode(), is(true));\n        assertThat(scheduler.isInStandbyMode(), is(true));\n\n        try {\n            remoteScheduler.shutdown(true);\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        remoteScheduler.shutdown();\n        try {\n            remoteScheduler.isShutdown();\n            fail(\"Shutting down a scheduler un-registers it in JMX\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n        assertThat(scheduler.isShutdown(), is(true));\n\n    }\n\n    @Test\n    void testJMXOperations() throws Exception {\n        remoteScheduler.clear();\n        assertThat(remoteScheduler.getJobGroupNames().isEmpty(), is(true));\n    }\n\n    @Test\n    void testUnsupportedMethods() {\n        try {\n            remoteScheduler.getListenerManager();\n            fail(\"Operation should not be supported\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.setJobFactory(null);\n            fail(\"Operation should not be supported\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n    }\n\n    @Test\n    void testListBrokenAttributes() throws Exception {\n        try {\n            remoteScheduler.getContext();\n            fail(\"Method was not exposed in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n        try {\n            remoteScheduler.getCurrentlyExecutingJobs();\n            fail(\"Method had a different return type in MBean API\");\n        } catch (SchedulerException e) {\n            // expected\n        }\n\n    }\n\n    public static class HelloJob implements Job {\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            System.out.println(\"hello world!\");\n        }\n    }\n\n    public static class TestRemoteScheduler extends RemoteMBeanScheduler {\n\n        private MBeanServer mBeanServer;\n        private ObjectName objectName;\n\n        public TestRemoteScheduler(String objectName) throws SchedulerException, MalformedObjectNameException {\n            this.objectName = new ObjectName(objectName);\n            initialize();\n        }\n\n        @Override\n        public void initialize() throws SchedulerException {\n            mBeanServer = ManagementFactory.getPlatformMBeanServer();\n        }\n\n        @Override\n        protected Object getAttribute(String attribute) throws SchedulerException {\n            try {\n                return mBeanServer.getAttribute(objectName, attribute);\n            } catch (Exception e) {\n                throw new SchedulerException(e);\n            }\n        }\n\n        @Override\n        protected AttributeList getAttributes(String[] attributes) throws SchedulerException {\n            try {\n                return mBeanServer.getAttributes(objectName, attributes);\n            } catch (Exception e) {\n                throw new SchedulerException(e);\n            }\n\n        }\n\n        @Override\n        protected Object invoke(String operationName, Object[] params, String[] signature) throws SchedulerException {\n            try {\n                return mBeanServer.invoke(objectName, operationName, params, signature);\n            } catch (Exception e) {\n                throw new SchedulerException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/SchedulerDetailsSetterTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.objectweb.asm.ClassWriter;\nimport org.objectweb.asm.MethodVisitor;\nimport org.objectweb.asm.Opcodes;\nimport org.quartz.SchedulerException;\nimport org.quartz.simpl.RAMJobStore;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.ThreadPool;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic class SchedulerDetailsSetterTest  {\n    @Test\n    void testSetter() throws SchedulerException, IOException {\n        Properties props = new Properties();\n        props.load(getClass().getResourceAsStream(\"/org/quartz/quartz.properties\"));\n        props.setProperty(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, MyThreadPool.class.getName());\n        props.setProperty(StdSchedulerFactory.PROP_JOB_STORE_CLASS, MyJobStore.class.getName());\n        \n        StdSchedulerFactory factory = new StdSchedulerFactory(props);\n        factory.getScheduler(); // this will initialize all the test fixtures.\n        \n        assertEquals(3, instanceIdCalls.get());\n        assertEquals(3, instanceNameCalls.get());\n\n        DirectSchedulerFactory directFactory = DirectSchedulerFactory.getInstance();\n        directFactory.createScheduler(\"SchedulerDetailsSetterTest.testSetter\", \"1\", new MyThreadPool(), new MyJobStore());\n\n        assertEquals(5, instanceIdCalls.get());\n        assertEquals(6, instanceNameCalls.get());\n    }\n    @Test\n    void testMissingSetterMethods() throws SchedulerException  {\n        SchedulerDetailsSetter.setDetails(new Object(), \"name\", \"id\");\n    }\n    @Test\n    void testUnimplementedMethods() throws Exception {\n        ThreadPool tp = makeIncompleteThreadPool();\n        try {\n            tp.setInstanceName(\"name\");\n            fail();\n        } catch (AbstractMethodError ame) {\n            // expected\n        }\n\n        SchedulerDetailsSetter.setDetails(tp, \"name\", \"id\");\n    }\n\n\n    private ThreadPool makeIncompleteThreadPool() throws InstantiationException, IllegalAccessException {\n        String name = \"IncompleteThreadPool\";\n        ClassWriter cw = new ClassWriter(0);\n        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, name, null, \"java/lang/Object\", new String[] { \"org/quartz/spi/ThreadPool\" });\n\n        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, \"<init>\", \"()V\", null, null);\n        mv.visitCode();\n        mv.visitVarInsn(Opcodes.ALOAD, 0);\n        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, \"java/lang/Object\", \"<init>\", \"()V\");\n        mv.visitInsn(Opcodes.RETURN);\n        mv.visitMaxs(1, 1);\n        mv.visitEnd();\n\n        cw.visitEnd();\n\n        return (ThreadPool) new ClassLoader() {\n            Class<?> defineClass(String clname, byte[] b) {\n                return defineClass(clname, b, 0, b.length);\n            }\n        }.defineClass(name, cw.toByteArray()).newInstance();\n    }\n\n    private static final AtomicInteger instanceIdCalls = new AtomicInteger();\n    private static final AtomicInteger instanceNameCalls = new AtomicInteger();\n\n    public static class MyThreadPool extends SimpleThreadPool {\n        \n        @Override\n        public void initialize() {\n        }\n\n        @Override\n        public void setInstanceId(String schedInstId) {\n            super.setInstanceId(schedInstId);\n            instanceIdCalls.incrementAndGet();\n        }\n\n        @Override\n        public void setInstanceName(String schedName) {\n            super.setInstanceName(schedName);\n            instanceNameCalls.incrementAndGet();\n        }\n    }\n\n\n    public static class MyJobStore extends RAMJobStore {\n\n        @Override\n        public void setInstanceId(String schedInstId) {\n            super.setInstanceId(schedInstId);\n            instanceIdCalls.incrementAndGet();\n        }\n\n        @Override\n        public void setInstanceName(String schedName) {\n            super.setInstanceName(schedName);\n            instanceNameCalls.incrementAndGet();\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/StdSchedulerFactoryCustomConnectionProviderTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\n/**\n * TestCase to verify StdSchedulerFactory initializes correctly a custom ConnectionProvider\n * \n * @author adahanne\n *\n */\n\nclass StdSchedulerFactoryCustomConnectionProviderTest {\n\n\t@Test\n\tvoid loadAndInitializeCustomConnectionProviderTest() throws SchedulerException, InterruptedException {\n\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/properties/quartzCustomConnectionProvider.properties\");\n\t\tScheduler scheduler = factory.getScheduler();\n\t\ttry{\n\t\t\tscheduler.start();\n\t\t} catch(Exception e){\n\t\t\t//the mock connection provider throws a MockSQLException\n\t\t\tassertEquals(\"org.quartz.impl.MockSQLException\",e.getCause().getCause().getClass().getName());\n\t\t}\n\t\tassertEquals(\"setCustomProperty(customValue)\",MockConnectionProvider.methodsCalled.get(0));\n\t\tassertEquals(\"initialize\",MockConnectionProvider.methodsCalled.get(1));\n\t\tassertEquals(\"getConnection\",MockConnectionProvider.methodsCalled.get(2));\n\t}\n\t\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/StdSchedulerFactoryTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl;\n\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.helpers.NOPLogger;\n\nclass StdSchedulerFactoryTest {\n\n\t@Test\n\tvoid testOverrideSystemProperties() {\n\t    Properties p = new Properties();\n\t    p.setProperty(\"nonsense1\", \"hello1\");\n\t    p.setProperty(\"nonsense2\", \"hello2\");\n\t    System.setProperty(\"nonsense1\", \"boo1\");\n\t    String osName = System.getProperty(\"os.name\");\n\t    Properties q = StdSchedulerFactory.overrideWithSysProps(p, NOPLogger.NOP_LOGGER);\n\t    assertEquals(\"boo1\", q.get(\"nonsense1\"));\n\t    assertEquals(osName, q.get(\"os.name\"));\n\t}\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/calendar/BaseCalendarTest.java",
    "content": "package org.quartz.impl.calendar;\n\n\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass BaseCalendarTest  {\n\n    @Test\n    void testClone() {\n        BaseCalendar base = new BaseCalendar();\n        BaseCalendar clone = (BaseCalendar) base.clone();\n\n        assertEquals(base.getDescription(), clone.getDescription());\n        assertEquals(base.getBaseCalendar(), clone.getBaseCalendar());\n        assertEquals(base.getTimeZone(), clone.getTimeZone());\n    }\n\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/calendar/DailyCalendarTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.impl.calendar;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.SerializationTestSupport;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n/**\n * Unit test for DailyCalendar.\n */\npublic class DailyCalendarTest extends SerializationTestSupport {\n    private static final String[] VERSIONS = new String[] {\"1.5.2\"};\n\n    @Test\n    void testStringStartEndTimes() {\n        DailyCalendar dailyCalendar = new DailyCalendar(\"1:20\", \"14:50\");\n        assertTrue(dailyCalendar.toString().indexOf(\"01:20:00:000 - 14:50:00:000\") > 0);\n        \n        dailyCalendar = new DailyCalendar(\"1:20:1:456\", \"14:50:15:2\");\n        assertTrue(dailyCalendar.toString().indexOf(\"01:20:01:456 - 14:50:15:002\") > 0);\n    }\n\n    @Test\n    void testStringInvertTimeRange() {\n        DailyCalendar dailyCalendar = new DailyCalendar(\"1:20\", \"14:50\");\n        dailyCalendar.setInvertTimeRange(true);\n        assertTrue(dailyCalendar.toString().indexOf(\"inverted: true\") > 0);\n\n        dailyCalendar.setInvertTimeRange(false);\n        assertTrue(dailyCalendar.toString().indexOf(\"inverted: false\") > 0);\n    }\n    \n    /**\n     * Get the object to serialize when generating serialized file for future\n     * tests, and against which to validate deserialized object.\n     */\n    @Override\n    protected Object getTargetObject() {\n        DailyCalendar c = new DailyCalendar(\"01:20:01:456\", \"14:50:15:002\");\n        c.setDescription(\"description\");\n        c.setInvertTimeRange(true);\n        \n        return c;\n    }\n    \n    /**\n     * Get the Quartz versions for which we should verify\n     * serialization backwards compatibility.\n     */\n    @Override\n    protected String[] getVersions() {\n        return VERSIONS;\n    }\n    \n    /**\n     * Verify that the target object and the object we just deserialized \n     * match.\n     */\n    @Override\n    protected void verifyMatch(Object target, Object deserialized) {\n        DailyCalendar targetCalendar = (DailyCalendar)target;\n        DailyCalendar deserializedCalendar = (DailyCalendar)deserialized;\n        \n        assertNotNull(deserializedCalendar);\n        assertEquals(targetCalendar.getDescription(), deserializedCalendar.getDescription());\n        assertTrue(deserializedCalendar.getInvertTimeRange());\n        assertNull(deserializedCalendar.getTimeZone());\n        assertTrue(deserializedCalendar.toString().indexOf(\"01:20:01:456 - 14:50:15:002\") > 0);\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/DeleteNonExistsJobTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.*;\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.SchedulerRepository;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.utils.DBConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\n/**\n * Tests for QTZ-326\n *\n * @author Zemian Deng\n */\npublic class DeleteNonExistsJobTest {\n    private static final Logger LOG = LoggerFactory.getLogger(DeleteNonExistsJobTest.class);\n    private static final String DB_NAME = \"DeleteNonExistsJobTestDatabase\";\n    private static String SCHEDULER_NAME = \"DeleteNonExistsJobTestScheduler\";\n    private static Scheduler scheduler;\n\n    @BeforeAll\n    public static void beforeClass() throws Exception {\n        JdbcQuartzTestUtilities.createDatabase(DB_NAME, DatabaseType.DERBY);\n    }\n\n    @BeforeEach\n    public void beforeTest() throws Exception {\n        resetDatabaseData();\n        JobStoreTX jobStore = new JobStoreTX();\n        jobStore.setDataSource(DB_NAME);\n        jobStore.setTablePrefix(\"QRTZ_\");\n        jobStore.setInstanceId(\"AUTO\");\n        DirectSchedulerFactory.getInstance().createScheduler(SCHEDULER_NAME, \"AUTO\",\n                new SimpleThreadPool(4, Thread.NORM_PRIORITY), jobStore);\n        scheduler = SchedulerRepository.getInstance().lookup(SCHEDULER_NAME);\n        // scheduler.start(); // Do not start scheduler to produce the defect case.\n    }\n\n    private void resetDatabaseData() throws Exception {\n        Connection conn = DBConnectionManager.getInstance().getConnection(DB_NAME);\n        Statement statement = conn.createStatement();\n        statement.addBatch(\"delete from qrtz_fired_triggers\");\n        statement.addBatch(\"delete from qrtz_paused_trigger_grps\");\n        statement.addBatch(\"delete from qrtz_scheduler_state\");\n        statement.addBatch(\"delete from qrtz_locks\");\n        statement.addBatch(\"delete from qrtz_simple_triggers\");\n        statement.addBatch(\"delete from qrtz_simprop_triggers\");\n        statement.addBatch(\"delete from qrtz_blob_triggers\");\n        statement.addBatch(\"delete from qrtz_cron_triggers\");\n        statement.addBatch(\"delete from qrtz_triggers\");\n        statement.addBatch(\"delete from qrtz_job_details\");\n        statement.addBatch(\"delete from qrtz_calendars\");\n        statement.executeBatch();\n        statement.close();\n        conn.close();\n    }\n\n    @AfterEach\n    public void afterTest() throws Exception {\n        scheduler.shutdown(true);\n    }\n\n    @Test\n    void deleteJobDetailOnly() throws Exception {\n        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(\"testjob\").storeDurably().build();\n        scheduler.addJob(jobDetail, true);\n        modifyStoredJobClassName();\n\n        scheduler.deleteJob(jobDetail.getKey());\n    }\n\n    @Test\n    void deleteJobDetailWithTrigger() throws Exception {\n        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(\"testjob2\").storeDurably().build();\n        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"testjob2\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\")).build();\n        scheduler.scheduleJob(jobDetail, trigger);\n        modifyStoredJobClassName();\n\n        scheduler.deleteJob(jobDetail.getKey());\n    }\n\n    @Test\n    void deleteTrigger() throws Exception {\n        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(\"testjob3\").storeDurably().build();\n        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"testjob3\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\")).build();\n        scheduler.scheduleJob(jobDetail, trigger);\n        modifyStoredJobClassName();\n\n        scheduler.unscheduleJob(trigger.getKey());\n    }\n\n    @Test\n    void replaceJobDetail() throws Exception {\n        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(\"testjob3\").storeDurably().build();\n        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"testjob3\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\")).build();\n        scheduler.scheduleJob(jobDetail, trigger);\n        modifyStoredJobClassName();\n\n        jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(\"testjob3\").storeDurably().build();\n        scheduler.addJob(jobDetail, true);\n    }\n\n    private void modifyStoredJobClassName() throws Exception {\n        Connection conn = DBConnectionManager.getInstance().getConnection(DB_NAME);\n        Statement statement = conn.createStatement();\n        statement.executeUpdate(\"update qrtz_job_details set job_class_name='com.FakeNonExistsJob'\");\n        statement.close();\n        conn.close();\n    }\n\n    public static class TestJob implements Job {\n\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            LOG.info(\"Job is executing {}\", context);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/GaussDBDelegateTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobDataMap;\nimport org.quartz.TriggerKey;\nimport org.quartz.simpl.SimpleClassLoadHelper;\nimport org.quartz.spi.OperableTrigger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.*;\n\n\npublic class GaussDBDelegateTest {\n\n    @Test\n    void testSelectBlobTriggerWithBlobContent() throws Exception {\n        StdJDBCDelegate jdbcDelegate = new GaussDBDelegate();\n        jdbcDelegate.initialize(LoggerFactory.getLogger(getClass()), \"QRTZ_\", \"TESTSCHED\", \"INSTANCE\",\n                new SimpleClassLoadHelper(), false, \"\");\n\n        Connection conn = mock(Connection.class);\n        PreparedStatement preparedStatement = mock(PreparedStatement.class);\n        ResultSet resultSet = mock(ResultSet.class);\n\n        when(conn.prepareStatement(anyString())).thenReturn(preparedStatement);\n        when(preparedStatement.executeQuery()).thenReturn(resultSet);\n\n        when(resultSet.next()).thenReturn(true).thenReturn(false);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_BLOB);\n        when(resultSet.getBytes(Constants.COL_JOB_DATAMAP)).thenReturn(null);\n\n        OperableTrigger trigger = jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"test\"));\n        assertNull(trigger);\n\n        reset(resultSet);\n\n        when(resultSet.next()).thenReturn(true).thenReturn(false);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_BLOB);\n        when(resultSet.getString(Constants.COL_TRIGGER_NAME)).thenReturn(\"testWithJobData\");\n        when(resultSet.getString(Constants.COL_TRIGGER_GROUP)).thenReturn(\"DEFAULT\");\n        when(resultSet.getString(Constants.COL_JOB_NAME)).thenReturn(\"testJob\");\n        when(resultSet.getString(Constants.COL_JOB_GROUP)).thenReturn(\"DEFAULT\");\n        when(resultSet.getLong(Constants.COL_NEXT_FIRE_TIME)).thenReturn(System.currentTimeMillis());\n        when(resultSet.getLong(Constants.COL_PREV_FIRE_TIME)).thenReturn(System.currentTimeMillis() - 1000);\n        when(resultSet.getString(Constants.COL_TRIGGER_STATE)).thenReturn(\"WAITING\");\n\n        JobDataMap jdm = new JobDataMap();\n        jdm.put(\"key1\", \"value\");\n        jdm.put(\"key2\", true);\n        byte[] jobDataMapBytes = serializeJobDataMap(jdm);\n        when(resultSet.getBytes(Constants.COL_JOB_DATAMAP)).thenReturn(jobDataMapBytes);\n\n        trigger = jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"testWithJobData\"));\n        assertNull(trigger);\n\n        reset(resultSet);\n\n        when(resultSet.next()).thenReturn(true).thenReturn(false);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_BLOB);\n        when(resultSet.getString(Constants.COL_TRIGGER_NAME)).thenReturn(\"testEmptyJobData\");\n        when(resultSet.getString(Constants.COL_TRIGGER_GROUP)).thenReturn(\"DEFAULT\");\n        when(resultSet.getString(Constants.COL_JOB_NAME)).thenReturn(\"testJob\");\n        when(resultSet.getString(Constants.COL_JOB_GROUP)).thenReturn(\"DEFAULT\");\n        when(resultSet.getBytes(Constants.COL_JOB_DATAMAP)).thenReturn(new byte[0]);\n\n        trigger = jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"testEmptyJobData\"));\n        assertNull(trigger);\n    }\n\n    private byte[] serializeJobDataMap(JobDataMap jobDataMap) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {\n            oos.writeObject(jobDataMap);\n        }\n        return baos.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/JdbcJobStoreTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.quartz.AbstractJobStoreTest;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.spi.JobStore;\n\npublic class JdbcJobStoreTest extends AbstractJobStoreTest {\n\n    private HashMap<String, JobStoreSupport> stores = new HashMap<String, JobStoreSupport>();\n\n    protected DatabaseType getDatabaseType() {\n        return DatabaseType.DERBY;\n    }\n\n    private String name(String prefix) {\n        return prefix + \"_\" + getDatabaseType().name();\n    }\n\n    @Override\n    protected JobStore createJobStore(String prefix) {\n        String name = name(prefix);\n        try {\n            JdbcQuartzTestUtilities.createDatabase(name, getDatabaseType());\n            JobStoreTX jdbcJobStore = new JobStoreTX();\n            jdbcJobStore.setDataSource(name);\n            jdbcJobStore.setTablePrefix(\"QRTZ_\");\n            jdbcJobStore.setInstanceId(\"SINGLE_NODE_TEST_\" + getDatabaseType().name());\n            jdbcJobStore.setInstanceName(name);\n            jdbcJobStore.setUseDBLocks(true);\n            jdbcJobStore.setDriverDelegateClass(getDatabaseType().getDelegateClassName());\n\n            stores.put(name, jdbcJobStore);\n\n            return jdbcJobStore;\n        } catch (Exception e) {\n            throw new AssertionError(e);\n        }\n    }\n\n    @Override\n    protected void destroyJobStore(String prefix) {\n        String name = name(prefix);\n        try {\n            JobStoreSupport jdbcJobStore = stores.remove(name);\n            jdbcJobStore.shutdown();\n\n            JdbcQuartzTestUtilities.destroyDatabase(name, getDatabaseType());\n        } catch (SQLException e) {\n            throw new AssertionError(e);\n        }\n    }\n\n    protected Map<String, JobStoreSupport> stores() {\n        return stores;\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/JdbcQuartzTestUtilities.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.EnumMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.quartz.utils.ConnectionProvider;\nimport org.quartz.utils.DBConnectionManager;\n\npublic final class JdbcQuartzTestUtilities {\n\n    public enum DatabaseType {\n        DERBY(\"org/quartz/impl/jdbcjobstore/tables_derby.sql\", StdJDBCDelegate.class.getName()),\n        MSSQL(\"org/quartz/impl/jdbcjobstore/tables_sqlServer.sql\", MSSQLDelegate.class.getName()),\n        MARIADB(\"org/quartz/impl/jdbcjobstore/tables_mysql.sql\", StdJDBCDelegate.class.getName()),\n        POSTGRES(\"org/quartz/impl/jdbcjobstore/tables_postgres.sql\", PostgreSQLDelegate.class.getName());\n\n        private final String scriptResource;\n        private final String delegateClassName;\n\n        DatabaseType(String scriptResource, String delegateClassName) {\n            this.scriptResource = scriptResource;\n            this.delegateClassName = delegateClassName;\n        }\n\n        public String getDelegateClassName() {\n            return this.delegateClassName;\n        }\n    }\n\n    private static final Map<DatabaseType, List<String>> DATABASE_SETUP_SCRIPTS = new EnumMap<>(DatabaseType.class);\n\n    private static List<String> getDatabaseSetupScript(DatabaseType type) {\n        return DATABASE_SETUP_SCRIPTS.computeIfAbsent(type, t -> {\n            List<String> commandList = new ArrayList<>();\n            String setupScript;\n            try {\n                InputStream setupStream = JdbcQuartzTestUtilities.class.getClassLoader()\n                        .getResourceAsStream(t.scriptResource);\n                try {\n                    BufferedReader r = new BufferedReader(new InputStreamReader(setupStream, \"US-ASCII\"));\n                    StringBuilder sb = new StringBuilder();\n                    while (true) {\n                        String line = r.readLine();\n                        if (line == null) {\n                            break;\n                        } else if (!line.startsWith(\"--\") && !line.startsWith(\"#\")) {\n                            // update script for some database like sql server to be executable with jdbc\n                            sb.append(line).append(\"\\n\");\n                        }\n                    }\n                    setupScript = sb.toString();\n                } finally {\n                    setupStream.close();\n                }\n            } catch (IOException e) {\n                throw new AssertionError(e);\n            }\n\n            for (String command : setupScript.split(\";\")) {\n                if (!command.matches(\"\\\\s*\")) {\n                    commandList.add(command);\n                }\n            }\n            return commandList;\n\n        });\n    }\n\n    public static void createDatabase(String name, DatabaseType databaseType) throws SQLException {\n        switch (databaseType) {\n            case DERBY:\n                DBConnectionManager.getInstance().addConnectionProvider(name, new DerbyEmbeddedConnectionProvider(name));\n                break;\n            case MSSQL:\n                DBConnectionManager.getInstance().addConnectionProvider(name,\n                        new TestContainerEmbeddedConnectionProvider(\"jdbc:tc:sqlserver:latest:///\" + name));\n                break;\n            case MARIADB:\n                DBConnectionManager.getInstance().addConnectionProvider(name,\n                        new TestContainerEmbeddedConnectionProvider(\"jdbc:tc:mariadb:latest:///\" + name));\n                break;\n            case POSTGRES:\n                DBConnectionManager.getInstance().addConnectionProvider(name,\n                        new TestContainerEmbeddedConnectionProvider(\"jdbc:tc:postgresql:latest:///\" + name));\n                break;\n            default:\n                throw new AssertionError(\"Unsupported database type: \" + databaseType);\n        }\n    }\n\n    public static void destroyDatabase(String name, DatabaseType databaseType) throws SQLException {\n        switch (databaseType) {\n            case DERBY:\n                try {\n                    DriverManager.getConnection(\"jdbc:derby:memory:\" + name + \";drop=true\").close();\n                } catch (SQLException e) {\n                    if (!(\"Database 'memory:\" + name + \"' dropped.\").equals(e.getMessage())) {\n                        throw e;\n                    }\n                }\n                break;\n            case MSSQL:\n            case MARIADB:\n            case POSTGRES:\n                shutdownDatabase(name, databaseType);\n                break;\n            default:\n                throw new AssertionError(\"Unsupported database type: \" + databaseType);\n        }\n    }\n\n    public static void shutdownDatabase(String name, DatabaseType databaseType) throws SQLException {\n        switch (databaseType) {\n            case DERBY:\n                try {\n                    DriverManager.getConnection(\"jdbc:derby:;shutdown=true\").close();\n                } catch (SQLException e) {\n                    if (!(\"Derby system shutdown.\").equals(e.getMessage())) {\n                        throw e;\n                    }\n                }\n                break;\n            case MSSQL:\n            case MARIADB:\n            case POSTGRES:\n                DBConnectionManager.getInstance().shutdown(name);\n                break;\n            default:\n                throw new AssertionError(\"Unsupported database type: \" + databaseType);\n        }\n    }\n\n    static class DerbyEmbeddedConnectionProvider implements ConnectionProvider {\n\n        private final String databaseName;\n\n        DerbyEmbeddedConnectionProvider(String name) throws SQLException {\n            try {\n                Class.forName(\"org.apache.derby.jdbc.EmbeddedDriver\").getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                throw new AssertionError(e);\n            }\n            this.databaseName = name;\n            Connection conn = DriverManager.getConnection(\"jdbc:derby:memory:\" + databaseName + \";create=true\");\n            try {\n                Statement statement = conn.createStatement();\n                for (String command : getDatabaseSetupScript(DatabaseType.DERBY)) {\n                    statement.addBatch(command);\n                }\n                statement.executeBatch();\n            } finally {\n                conn.close();\n            }\n        }\n\n        public Connection getConnection() throws SQLException {\n            return DriverManager.getConnection(\"jdbc:derby:memory:\" + databaseName);\n        }\n\n        public void shutdown() throws SQLException {\n            // nothing to do\n        }\n\n        public void initialize() throws SQLException {\n            // nothing to do\n        }\n    }\n\n    static class TestContainerEmbeddedConnectionProvider implements ConnectionProvider {\n\n        private final String jdbcUrl;\n        //we keep a connection open to keep the testcontainer container alive\n        private final Connection conn;\n\n        TestContainerEmbeddedConnectionProvider(String jdbcUrl) throws SQLException {\n            this.jdbcUrl = jdbcUrl;\n            this.conn = DriverManager.getConnection(this.jdbcUrl);\n\n            Statement statement = conn.createStatement();\n            if(jdbcUrl.contains(\"sqlserver\")) {\n                for (String command : getDatabaseSetupScript(DatabaseType.MSSQL)) {\n                    statement.addBatch(command.replace(\"GO\", \";\").replace(\"[enter_db_name_here]\", \"[master]\"));\n                }\n            } else if(jdbcUrl.contains(\"mariadb\")) {\n                for (String command : getDatabaseSetupScript(DatabaseType.MARIADB)) {\n                    statement.addBatch(command);\n                }\n            } else if(jdbcUrl.contains(\"postgresql\")) {\n                for (String command : getDatabaseSetupScript(DatabaseType.POSTGRES)) {\n                    statement.addBatch(command);\n                }\n            }\n            statement.executeBatch();\n        }\n\n        public Connection getConnection() throws SQLException {\n            return DriverManager.getConnection(this.jdbcUrl);\n        }\n\n        public void shutdown() throws SQLException {\n            // last connection closed shutdown testcontainer container\n            if (!conn.isClosed()) {\n                conn.close();\n            }\n        }\n\n        public void initialize() throws SQLException {\n            // nothing to do\n        }\n    }\n\n    private JdbcQuartzTestUtilities() {\n        // not instantiable\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/MSSQLJdbcStoreTest.java",
    "content": "/* \n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\n\npublic class MSSQLJdbcStoreTest extends JdbcJobStoreTest {\n    @Override\n    protected DatabaseType getDatabaseType() {\n        return DatabaseType.MSSQL;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/MariaDBJdbcStoreTest.java",
    "content": "/* \n * Copyright IBM Corp. 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\n\npublic class MariaDBJdbcStoreTest extends JdbcJobStoreTest {\n    @Override\n    protected DatabaseType getDatabaseType() {\n        return DatabaseType.MARIADB;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/PostgresJdbcStoreTest.java",
    "content": "/* \n * Copyright IBM Corp. 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\n\npublic class PostgresJdbcStoreTest extends JdbcJobStoreTest {\n    @Override\n    protected DatabaseType getDatabaseType() {\n        return DatabaseType.POSTGRES;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/StdJDBCDelegateTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.collection.IsIterableWithSize.iterableWithSize;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.io.NotSerializableException;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobPersistenceException;\nimport org.quartz.TriggerKey;\nimport org.quartz.spi.OperableTrigger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.JobDataMap;\nimport org.quartz.simpl.SimpleClassLoadHelper;\n\n\n\npublic class StdJDBCDelegateTest  {\n\n    @Test\n    void testSerializeJobData() throws IOException, NoSuchDelegateException {\n        StdJDBCDelegate delegate = new StdJDBCDelegate();\n        delegate.initialize(LoggerFactory.getLogger(getClass()), \"QRTZ_\", \"TESTSCHED\", \"INSTANCE\", new SimpleClassLoadHelper(), false, \"\");\n        \n        JobDataMap jdm = new JobDataMap();\n        delegate.serializeJobData(jdm).close();\n\n        jdm.clear();\n        jdm.put(\"key\", \"value\");\n        jdm.put(\"key2\", null);\n        delegate.serializeJobData(jdm).close();\n\n        jdm.clear();\n        jdm.put(\"key1\", \"value\");\n        jdm.put(\"key2\", null);\n        jdm.put(\"key3\", new Object());\n        try {\n            delegate.serializeJobData(jdm);\n            fail();\n        } catch (NotSerializableException e) {\n            assertTrue(e.getMessage().indexOf(\"key3\") >= 0);\n        }\n    }\n\n    @Test\n    void testSelectBlobTriggerWithNoBlobContent() throws JobPersistenceException, SQLException, IOException, ClassNotFoundException {\n        StdJDBCDelegate jdbcDelegate = new StdJDBCDelegate();\n        jdbcDelegate.initialize(LoggerFactory.getLogger(getClass()), \"QRTZ_\", \"TESTSCHED\", \"INSTANCE\", new SimpleClassLoadHelper(), false, \"\");\n\n        Connection conn = mock(Connection.class);\n        PreparedStatement preparedStatement = mock(PreparedStatement.class);\n        ResultSet resultSet = mock(ResultSet.class);\n\n        when(conn.prepareStatement(anyString())).thenReturn(preparedStatement);\n\n        when(preparedStatement.executeQuery()).thenReturn(resultSet);\n        // First result set has results, second has none\n        when(resultSet.next()).thenReturn(true).thenReturn(false);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_BLOB);\n\n        OperableTrigger trigger = jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"test\"));\n        assertNull(trigger);\n\n    }\n    @Test\n    void testSelectSimpleTriggerWithExceptionWithExtendedProps() throws SQLException, JobPersistenceException, IOException, ClassNotFoundException {\n        TriggerPersistenceDelegate persistenceDelegate = mock(TriggerPersistenceDelegate.class);\n        IllegalStateException exception = new IllegalStateException();\n        when(persistenceDelegate.loadExtendedTriggerProperties(any(Connection.class), any(TriggerKey.class))).thenThrow(exception);\n\n        StdJDBCDelegate jdbcDelegate = new TestStdJDBCDelegate(persistenceDelegate);\n        jdbcDelegate.initialize(LoggerFactory.getLogger(getClass()), \"QRTZ_\", \"TESTSCHED\", \"INSTANCE\", new SimpleClassLoadHelper(), false, \"\");\n\n        Connection conn = mock(Connection.class);\n        PreparedStatement preparedStatement = mock(PreparedStatement.class);\n        ResultSet resultSet = mock(ResultSet.class);\n\n        when(conn.prepareStatement(anyString())).thenReturn(preparedStatement);\n\n        // Mock basic trigger data\n        when(preparedStatement.executeQuery()).thenReturn(resultSet);\n        when(resultSet.next()).thenReturn(true);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_SIMPLE);\n\n        try {\n            jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"test\"));\n            fail(\"Trigger selection should result in exception\");\n        } catch (IllegalStateException e) {\n            assertSame(exception, e);\n        }\n        verify(persistenceDelegate).loadExtendedTriggerProperties(any(Connection.class), any(TriggerKey.class));\n\n    }\n    @Test\n    void testSelectSimpleTriggerWithDeleteBeforeSelectExtendedProps() throws JobPersistenceException, ClassNotFoundException, SQLException, IOException {\n        TriggerPersistenceDelegate persistenceDelegate = mock(TriggerPersistenceDelegate.class);\n        when(persistenceDelegate.loadExtendedTriggerProperties(any(Connection.class), any(TriggerKey.class))).thenThrow(new IllegalStateException());\n\n        StdJDBCDelegate jdbcDelegate = new TestStdJDBCDelegate(persistenceDelegate);\n        jdbcDelegate.initialize(LoggerFactory.getLogger(getClass()), \"QRTZ_\", \"TESTSCHED\", \"INSTANCE\", new SimpleClassLoadHelper(), false, \"\");\n\n        Connection conn = mock(Connection.class);\n        PreparedStatement preparedStatement = mock(PreparedStatement.class);\n        ResultSet resultSet = mock(ResultSet.class);\n\n        when(conn.prepareStatement(anyString())).thenReturn(preparedStatement);\n\n        when(preparedStatement.executeQuery()).thenReturn(resultSet);\n        // First result set has results, second has none\n        when(resultSet.next()).thenReturn(true).thenReturn(false);\n        when(resultSet.getString(Constants.COL_TRIGGER_TYPE)).thenReturn(Constants.TTYPE_SIMPLE);\n\n        OperableTrigger trigger = jdbcDelegate.selectTrigger(conn, TriggerKey.triggerKey(\"test\"));\n        assertNull(trigger);\n        verify(persistenceDelegate).loadExtendedTriggerProperties(any(Connection.class), any(TriggerKey.class));\n    }\n    @Test\n    void testSelectTriggerToAcquireHonorsMaxCount() throws SQLException {\n\n        StdJDBCDelegate jdbcDelegate = new StdJDBCDelegate();\n\n        Connection conn = mock(Connection.class);\n        PreparedStatement preparedStatement = mock(PreparedStatement.class);\n        ResultSet resultSet = mock(ResultSet.class);\n\n        when(conn.prepareStatement(anyString())).thenReturn(preparedStatement);\n\n        when(preparedStatement.executeQuery()).thenReturn(resultSet);\n\n        when(resultSet.next()).thenReturn(true);\n        when(resultSet.getString(anyString())).thenReturn(\"test\");\n\n        List<TriggerKey> triggerKeys = jdbcDelegate.selectTriggerToAcquire(conn, Long.MAX_VALUE, Long.MIN_VALUE, 10);\n\n        assertThat(triggerKeys, iterableWithSize(10));\n    }\n\n    static class TestStdJDBCDelegate extends StdJDBCDelegate {\n\n        private final TriggerPersistenceDelegate testDelegate;\n\n        public TestStdJDBCDelegate(TriggerPersistenceDelegate testDelegate) {\n            this.testDelegate = testDelegate;\n        }\n\n        @Override\n        public TriggerPersistenceDelegate findTriggerPersistenceDelegate(String discriminator) {\n            return testDelegate;\n        }\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/jdbcjobstore/UpdateLockRowSemaphoreTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.impl.jdbcjobstore;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.startsWith;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n\nimport org.junit.jupiter.api.Test;\n\n/**\n *\n * @author cdennis\n */\nclass UpdateLockRowSemaphoreTest {\n  \n  private static final PreparedStatement GOOD_STATEMENT = mock(PreparedStatement.class);\n  private static final PreparedStatement FAIL_STATEMENT = mock(PreparedStatement.class);\n  private static final PreparedStatement BAD_STATEMENT = mock(PreparedStatement.class);\n\n  static {\n    try {\n      when(GOOD_STATEMENT.executeUpdate()).thenReturn(1);\n      when(FAIL_STATEMENT.executeUpdate()).thenReturn(0);\n      when(BAD_STATEMENT.executeUpdate()).thenThrow(SQLException.class);\n    } catch (SQLException e) {\n      throw new AssertionError(e);\n    }\n  }\n  \n  @Test\n  void testSingleSuccessUsingUpdate() throws LockException, SQLException {\n    UpdateLockRowSemaphore semaphore = new UpdateLockRowSemaphore();\n    semaphore.setSchedName(\"test\");\n\n    Connection mockConnection = mock(Connection.class);\n    when(mockConnection.prepareStatement(startsWith(\"UPDATE\")))\n            .thenReturn(GOOD_STATEMENT)\n            .thenThrow(AssertionError.class);\n    \n    assertTrue(semaphore.obtainLock(mockConnection, \"test\"));\n  }\n  \n  @Test\n  void testSingleFailureFollowedBySuccessUsingUpdate() throws LockException, SQLException {\n    UpdateLockRowSemaphore semaphore = new UpdateLockRowSemaphore();\n    semaphore.setSchedName(\"test\");\n\n    Connection mockConnection = mock(Connection.class);\n    when(mockConnection.prepareStatement(startsWith(\"UPDATE\")))\n            .thenReturn(BAD_STATEMENT)\n            .thenReturn(GOOD_STATEMENT)\n            .thenThrow(AssertionError.class);\n    \n    assertTrue(semaphore.obtainLock(mockConnection, \"test\"));\n  }\n\n  @Test\n  void testDoubleFailureFollowedBySuccessUsingUpdate() throws LockException, SQLException {\n    UpdateLockRowSemaphore semaphore = new UpdateLockRowSemaphore();\n    semaphore.setSchedName(\"test\");\n\n    Connection mockConnection = mock(Connection.class);\n    when(mockConnection.prepareStatement(startsWith(\"UPDATE\")))\n            .thenReturn(BAD_STATEMENT, BAD_STATEMENT)\n            .thenThrow(AssertionError.class);\n    \n    try {\n      semaphore.obtainLock(mockConnection, \"test\");\n      fail();\n    } catch (LockException e) {\n      //expected\n    }\n  }\n  \n  @Test\n  void testFallThroughToInsert() throws SQLException, LockException {\n    UpdateLockRowSemaphore semaphore = new UpdateLockRowSemaphore();\n    semaphore.setSchedName(\"test\");\n\n    Connection mockConnection = mock(Connection.class);\n    when(mockConnection.prepareStatement(startsWith(\"UPDATE\")))\n            .thenReturn(FAIL_STATEMENT)\n            .thenThrow(AssertionError.class);\n    when(mockConnection.prepareStatement(startsWith(\"INSERT\")))\n            .thenReturn(GOOD_STATEMENT)\n            .thenThrow(AssertionError.class);\n    \n    assertTrue(semaphore.obtainLock(mockConnection, \"test\"));\n  }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/matchers/GroupMatcherTest.java",
    "content": "/* \r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n * \r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \r\n * use this file except in compliance with the License. You may obtain a copy \r\n * of the License at \r\n * \r\n *   http://www.apache.org/licenses/LICENSE-2.0 \r\n *   \r\n * Unless required by applicable law or agreed to in writing, software \r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \r\n * License for the specific language governing permissions and limitations \r\n * under the License.\r\n * \r\n */\r\npackage org.quartz.impl.matchers;\r\n\r\n\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.quartz.JobKey;\r\nimport org.quartz.TriggerKey;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.quartz.JobKey.jobKey;\r\nimport static org.quartz.TriggerKey.triggerKey;\r\nimport static org.quartz.impl.matchers.GroupMatcher.anyJobGroup;\r\nimport static org.quartz.impl.matchers.GroupMatcher.anyTriggerGroup;\r\n\r\n/**\r\n * Unit test for CronScheduleBuilder.\r\n * \r\n * @author jhouse\r\n *\r\n */\r\nclass GroupMatcherTest  {\r\n\r\n    @Test\r\n\tvoid testAnyGroupMatchers() {\r\n\r\n        TriggerKey tKey = triggerKey(\"booboo\", \"baz\");\r\n        JobKey jKey = jobKey(\"frumpwomp\", \"bazoo\");\r\n\r\n        GroupMatcher tgm = anyTriggerGroup();\r\n        GroupMatcher jgm = anyJobGroup();\r\n\r\n        assertTrue(tgm.isMatch(tKey), \"Expected match on trigger group\");\r\n        assertTrue(jgm.isMatch(jKey), \"Expected match on job group\");\r\n\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/impl/triggers/DailyTimeIntervalTriggerImplTest.java",
    "content": "/* \r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n * \r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \r\n * use this file except in compliance with the License. You may obtain a copy \r\n * of the License at \r\n * \r\n *   http://www.apache.org/licenses/LICENSE-2.0 \r\n *   \r\n * Unless required by applicable law or agreed to in writing, software \r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \r\n * License for the specific language governing permissions and limitations \r\n * under the License.\r\n * \r\n */\r\npackage org.quartz.impl.triggers;\r\n\r\nimport static org.junit.jupiter.api.Assertions.*;\r\nimport static org.quartz.DateBuilder.dateOf;\r\n\r\nimport java.util.Calendar;\r\nimport java.util.Date;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\nimport java.util.Set;\r\n\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.junit.jupiter.params.ParameterizedTest;\r\nimport org.junit.jupiter.params.provider.ValueSource;\r\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\r\nimport org.quartz.DailyTimeIntervalTrigger;\r\nimport org.quartz.DateBuilder;\r\nimport org.quartz.DateBuilder.IntervalUnit;\r\nimport org.quartz.JobKey;\r\nimport org.quartz.SchedulerException;\r\nimport org.quartz.TimeOfDay;\r\nimport org.quartz.TriggerUtils;\r\nimport org.quartz.impl.calendar.CronCalendar;\r\n\r\n/**\r\n * Unit test for {@link DailyTimeIntervalTriggerImpl}.\r\n * \r\n * @author Zemian Deng <saltnlight5@gmail.com>\r\n */\r\nclass DailyTimeIntervalTriggerImplTest  {\r\n\r\n  @Test\r\n  void testNormalExample() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(11, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(72); // this interval will give three firings per day (8:00, 9:12, and 10:24)\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(10, 24, 0, 16, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testQuartzCalendarExclusion() throws Exception {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(new TimeOfDay(8, 0));\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    CronCalendar cronCal = new CronCalendar(\"* * 9-12 * * ?\"); // exclude 9-12    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, cronCal, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(13, 0, 0, 1, 1, 2011), fireTimes.get(1));\r\n    assertEquals(dateOf(23, 0, 0, 4, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testValidateTimeOfDayOrder() {\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTimeOfDay(new TimeOfDay(12, 0, 0));\r\n    trigger.setEndTimeOfDay(new TimeOfDay(8, 0, 0));\r\n    try {\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when time of day is not in order.\");\r\n    } catch (SchedulerException e) {\r\n      // expected.\r\n    }\r\n  }\r\n\r\n  @Test\r\n  void testValidateInterval() throws Exception {\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setName(\"test\");\r\n    trigger.setGroup(\"test\");\r\n    trigger.setJobKey(JobKey.jobKey(\"test\"));\r\n    \r\n    trigger.setRepeatIntervalUnit(IntervalUnit.HOUR);\r\n    trigger.setRepeatInterval(25);\r\n    try {\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when interval is greater than 24 hours.\");\r\n    } catch (SchedulerException e) {\r\n      // expected.\r\n    }\r\n    \r\n    trigger.setRepeatIntervalUnit(IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60 * 25);\r\n    try {\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when interval is greater than 24 hours.\");\r\n    } catch (SchedulerException e) {\r\n      // expected.\r\n    }\r\n\r\n    trigger.setRepeatIntervalUnit(IntervalUnit.SECOND);\r\n    trigger.setRepeatInterval(60 * 60 * 25);\r\n    try {\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when interval is greater than 24 hours.\");\r\n    } catch (SchedulerException e) {\r\n      // expected.\r\n    }\r\n    \r\n    try {\r\n      trigger.setRepeatIntervalUnit(IntervalUnit.DAY);\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when interval unit > HOUR.\");\r\n    } catch (Exception e) {\r\n      // expected.\r\n    }\r\n\r\n    try {\r\n      trigger.setRepeatIntervalUnit(IntervalUnit.SECOND);\r\n      trigger.setRepeatInterval(0);\r\n      trigger.validate();\r\n      fail(\"Trigger should be invalidate when interval is zero.\");\r\n    } catch (Exception e) {\r\n      // expected.\r\n    }\r\n  }\r\n\r\n  @Test\r\n  void testStartTimeWithoutStartTimeOfDay() throws Exception {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(0, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(23, 0, 0, 2, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testEndTimeWithoutEndTimeOfDay() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(22, 0, 0, 2, 1, 2011);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(47, fireTimes.size());\r\n    assertEquals(dateOf(0, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(22, 0, 0, 2, 1, 2011), fireTimes.get(46));\r\n  }\r\n\r\n  @Test\r\n  void testStartTimeBeforeStartTimeOfDay() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(23, 0, 0, 3, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testStartTimeBeforeStartTimeOfDayOnInvalidDay() throws Exception {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011); // Jan 1, 2011 was a saturday...\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    Set<Integer> daysOfWeek = new HashSet<Integer>();\r\n    daysOfWeek.add(DateBuilder.MONDAY);\r\n    daysOfWeek.add(DateBuilder.TUESDAY);\r\n    daysOfWeek.add(DateBuilder.WEDNESDAY);\r\n    daysOfWeek.add(DateBuilder.THURSDAY);\r\n    daysOfWeek.add(DateBuilder.FRIDAY);\r\n    trigger.setDaysOfWeek(daysOfWeek);\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    assertEquals(dateOf(8, 0, 0, 3, 1, 2011), trigger.getFireTimeAfter(dateOf(6, 0, 0, 22, 5, 2010)));\r\n\r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 3, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(23, 0, 0, 5, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testStartTimeAfterStartTimeOfDay() {\r\n    Date startTime = dateOf(9, 23, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(10, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(9, 0, 0, 4, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testEndTimeBeforeEndTimeOfDay() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(16, 0, 0, 2, 1, 2011);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(35, fireTimes.size());\r\n    assertEquals(dateOf(0, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(17, 0, 0, 1, 1, 2011), fireTimes.get(17));\r\n    assertEquals(dateOf(16, 0, 0, 2, 1, 2011), fireTimes.get(34));\r\n  }\r\n\r\n  @Test\r\n  void testEndTimeAfterEndTimeOfDay() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(18, 0, 0, 2, 1, 2011);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(36, fireTimes.size());\r\n    assertEquals(dateOf(0, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(17, 0, 0, 1, 1, 2011), fireTimes.get(17));\r\n    assertEquals(dateOf(17, 0, 0, 2, 1, 2011), fireTimes.get(35));\r\n  }\r\n\r\n  @Test\r\n  void testTimeOfDayWithStartTime() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(17, 0, 0, 1, 1, 2011), fireTimes.get(9)); // The 10th hours is the end of day.\r\n    assertEquals(dateOf(15, 0, 0, 5, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testTimeOfDayWithEndTime() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(0, 0, 0, 4, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(30, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(17, 0, 0, 1, 1, 2011), fireTimes.get(9)); // The 10th hours is the end of day.\r\n    assertEquals(dateOf(17, 0, 0, 3, 1, 2011), fireTimes.get(29));\r\n  }\r\n\r\n  @Test\r\n  void testTimeOfDayWithEndTime2() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 23, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(23, 59, 59); // edge case when endTime is last second of day, which is default too.\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());    \r\n    assertEquals(dateOf(8, 23, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(23, 23, 0, 3, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testAllDaysOfTheWeek() {\r\n    Set<Integer> daysOfWeek = DailyTimeIntervalScheduleBuilder.ALL_DAYS_OF_THE_WEEK;\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011); // SAT\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setDaysOfWeek(daysOfWeek);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(17, 0, 0, 1, 1, 2011), fireTimes.get(9)); // The 10th hours is the end of day.\r\n    assertEquals(dateOf(15, 0, 0, 5, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testMonThroughFri() {\r\n    Set<Integer> daysOfWeek = DailyTimeIntervalScheduleBuilder.MONDAY_THROUGH_FRIDAY;\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011); // SAT(7)\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setDaysOfWeek(daysOfWeek);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 3, 1, 2011), fireTimes.get(0));\r\n    assertEquals(Calendar.MONDAY, getDayOfWeek(fireTimes.get(0)));\r\n    assertEquals(dateOf(8, 0, 0, 4, 1, 2011), fireTimes.get(10));\r\n    assertEquals(Calendar.TUESDAY, getDayOfWeek(fireTimes.get(10)));\r\n    assertEquals(dateOf(15, 0, 0, 7, 1, 2011), fireTimes.get(47));\r\n    assertEquals(Calendar.FRIDAY, getDayOfWeek(fireTimes.get(47)));\r\n  }\r\n\r\n  @Test\r\n  void testSatAndSun() {\r\n    Set<Integer> daysOfWeek = DailyTimeIntervalScheduleBuilder.SATURDAY_AND_SUNDAY;\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011); // SAT(7)\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setDaysOfWeek(daysOfWeek);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(Calendar.SATURDAY, getDayOfWeek(fireTimes.get(0)));\r\n    assertEquals(dateOf(8, 0, 0, 2, 1, 2011), fireTimes.get(10));\r\n    assertEquals(Calendar.SUNDAY, getDayOfWeek(fireTimes.get(10)));\r\n    assertEquals(dateOf(15, 0, 0, 15, 1, 2011), fireTimes.get(47));\r\n    assertEquals(Calendar.SATURDAY, getDayOfWeek(fireTimes.get(47)));\r\n  }\r\n\r\n  @Test\r\n  void testMonOnly() {\r\n    Set<Integer> daysOfWeek = new HashSet<Integer>();\r\n    daysOfWeek.add(Calendar.MONDAY);\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011); // SAT(7)\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setDaysOfWeek(daysOfWeek);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(60);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 3, 1, 2011), fireTimes.get(0));\r\n    assertEquals(Calendar.MONDAY, getDayOfWeek(fireTimes.get(0)));\r\n    assertEquals(dateOf(8, 0, 0, 10, 1, 2011), fireTimes.get(10));\r\n    assertEquals(Calendar.MONDAY, getDayOfWeek(fireTimes.get(10)));\r\n    assertEquals(dateOf(15, 0, 0, 31, 1, 2011), fireTimes.get(47));\r\n    assertEquals(Calendar.MONDAY, getDayOfWeek(fireTimes.get(47)));\r\n  }\r\n\r\n\r\n  private int getDayOfWeek(Date dateTime) {\r\n    Calendar cal = Calendar.getInstance();\r\n    cal.setTime(dateTime);\r\n    return cal.get(Calendar.DAY_OF_WEEK);\r\n  }\r\n\r\n  @Test\r\n  void testTimeOfDayWithEndTimeOddInterval() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(0, 0, 0, 4, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(10, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(23);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(18, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(9, 55, 0, 1, 1, 2011), fireTimes.get(5));\r\n    assertEquals(dateOf(9, 55, 0, 3, 1, 2011), fireTimes.get(17));\r\n  }\r\n\r\n  @Test\r\n  void testHourInterval() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    Date endTime = dateOf(13, 0, 0, 15, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 1, 15);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(16, 1, 15);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTime(endTime);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.HOUR);\r\n    trigger.setRepeatInterval(2);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 1, 15, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(12, 1, 15, 10, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testSecondInterval() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 2);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(13, 30, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.SECOND);\r\n    trigger.setRepeatInterval(72);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 2, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(8, 56, 26, 1, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testRepeatCountInf() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(11, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(72);\r\n    \r\n    // Setting this (which is default) should make the trigger just as normal one.\r\n    trigger.setRepeatCount(DailyTimeIntervalTrigger.REPEAT_INDEFINITELY);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);\r\n    assertEquals(48, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(10, 24, 0, 16, 1, 2011), fireTimes.get(47));\r\n  }\r\n\r\n  @Test\r\n  void testRepeatCount() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(11, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(72);\r\n    trigger.setRepeatCount(7);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);    \r\n    assertEquals(8, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n    assertEquals(dateOf(9, 12, 0, 3, 1, 2011), fireTimes.get(7));\r\n  }\r\n\r\n  @Test\r\n  void testRepeatCount0() {\r\n    Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n    TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n    TimeOfDay endTimeOfDay = new TimeOfDay(11, 0, 0);\r\n    DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n    trigger.setStartTime(startTime);\r\n    trigger.setStartTimeOfDay(startTimeOfDay);\r\n    trigger.setEndTimeOfDay(endTimeOfDay);\r\n    trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.MINUTE);\r\n    trigger.setRepeatInterval(72);\r\n    trigger.setRepeatCount(0);\r\n    \r\n    List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 48);    \r\n    assertEquals(1, fireTimes.size());\r\n    assertEquals(dateOf(8, 0, 0, 1, 1, 2011), fireTimes.get(0));\r\n  }\r\n\r\n  @Test\r\n  void testGetFireTime() {\r\n        Date startTime = dateOf(0, 0, 0, 1, 1, 2011);\r\n        TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n        TimeOfDay endTimeOfDay = new TimeOfDay(13, 0, 0);\r\n        DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n        trigger.setStartTime(startTime);\r\n        trigger.setStartTimeOfDay(startTimeOfDay);\r\n        trigger.setEndTimeOfDay(endTimeOfDay);\r\n        trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.HOUR);\r\n        trigger.setRepeatInterval(1);\r\n\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(0, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(7, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(7, 59, 59, 1, 1, 2011)));\r\n        assertEquals(dateOf(9, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(8, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(10, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(9, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(13, 0, 0, 1, 1, 2011), trigger.getFireTimeAfter(dateOf(12, 59, 59, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 2, 1, 2011), trigger.getFireTimeAfter(dateOf(13, 0, 0, 1, 1, 2011)));\r\n    }\r\n\r\n  @Test\r\n  void testGetFireTimeWithDateBeforeStartTime() {\r\n        Date startTime = dateOf(0, 0, 0, 1, 1, 2012);\r\n        TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n        TimeOfDay endTimeOfDay = new TimeOfDay(13, 0, 0);\r\n        DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n        trigger.setStartTime(startTime);\r\n        trigger.setStartTimeOfDay(startTimeOfDay);\r\n        trigger.setEndTimeOfDay(endTimeOfDay);\r\n        trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.HOUR);\r\n        trigger.setRepeatInterval(1);\r\n\r\n        // NOTE that if you pass a date past the startTime, you will get the first firing on or after the startTime back!\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(0, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(7, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(7, 59, 59, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(8, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(9, 0, 0, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(12, 59, 59, 1, 1, 2011)));\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(13, 0, 0, 1, 1, 2011)));\r\n\r\n        // Now try some test times at or after startTime\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(0, 0, 0, 1, 1, 2012)));\r\n        assertEquals(dateOf(8, 0, 0, 2, 1, 2012), trigger.getFireTimeAfter(dateOf(13, 0, 0, 1, 1, 2012)));\r\n    }\r\n\r\n  @Test\r\n  void testGetFireTimeWhenStartTimeAndTimeOfDayIsSame() {\r\n        // A test case for QTZ-369\r\n        Date startTime = dateOf(8, 0, 0, 1, 1, 2012);\r\n        TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);\r\n        TimeOfDay endTimeOfDay = new TimeOfDay(13, 0, 0);\r\n        DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n        trigger.setStartTime(startTime);\r\n        trigger.setStartTimeOfDay(startTimeOfDay);\r\n        trigger.setEndTimeOfDay(endTimeOfDay);\r\n        trigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.HOUR);\r\n        trigger.setRepeatInterval(1);\r\n\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getFireTimeAfter(dateOf(0, 0, 0, 1, 1, 2012)));\r\n    }\r\n\r\n  @Test\r\n  void testExtraConstructors() {\r\n        // A test case for QTZ-389 - some extra constructors didn't set all parameters\r\n        DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl(\r\n                \"triggerName\", \"triggerGroup\", \"jobName\", \"jobGroup\",\r\n                dateOf(8, 0, 0, 1, 1, 2012), null,\r\n                new TimeOfDay(8, 0, 0), new TimeOfDay(17, 0, 0),\r\n                IntervalUnit.HOUR, 1);\r\n\r\n        assertEquals(\"triggerName\", trigger.getName());\r\n        assertEquals(\"triggerGroup\", trigger.getGroup());\r\n        assertEquals(\"jobName\", trigger.getJobName());\r\n        assertEquals(\"jobGroup\", trigger.getJobGroup());\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getStartTime());\r\n        assertNull(trigger.getEndTime());\r\n        assertEquals(new TimeOfDay(8, 0, 0), trigger.getStartTimeOfDay());\r\n        assertEquals(new TimeOfDay(17, 0, 0), trigger.getEndTimeOfDay());\r\n        assertEquals(IntervalUnit.HOUR, trigger.getRepeatIntervalUnit());\r\n        assertEquals(1, trigger.getRepeatInterval());\r\n\r\n        trigger = new DailyTimeIntervalTriggerImpl(\r\n                \"triggerName\", \"triggerGroup\",\r\n                dateOf(8, 0, 0, 1, 1, 2012), null,\r\n                new TimeOfDay(8, 0, 0), new TimeOfDay(17, 0, 0),\r\n                IntervalUnit.HOUR, 1);\r\n\r\n        assertEquals(\"triggerName\", trigger.getName());\r\n        assertEquals(\"triggerGroup\", trigger.getGroup());\r\n        assertNull(trigger.getJobName());\r\n        assertEquals(\"DEFAULT\", trigger.getJobGroup());\r\n        assertEquals(dateOf(8, 0, 0, 1, 1, 2012), trigger.getStartTime());\r\n        assertNull(trigger.getEndTime());\r\n        assertEquals(new TimeOfDay(8, 0, 0), trigger.getStartTimeOfDay());\r\n        assertEquals(new TimeOfDay(17, 0, 0), trigger.getEndTimeOfDay());\r\n        assertEquals(IntervalUnit.HOUR, trigger.getRepeatIntervalUnit());\r\n        assertEquals(1, trigger.getRepeatInterval());\r\n    }\r\n\r\n    @ParameterizedTest\r\n    @ValueSource(ints = { Integer.MIN_VALUE, 0})\r\n    void testSetRepeatIntervalWithInvalidValues(int repeatInterval) {\r\n        DailyTimeIntervalTriggerImpl trigger = new DailyTimeIntervalTriggerImpl();\r\n        assertThrows(IllegalArgumentException.class, () -> trigger.setRepeatInterval(repeatInterval));\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/HelloJob.java",
    "content": "package org.quartz.integrations.tests;\n\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\nimport java.util.Date;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that says \"Hello\" to the world.\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class HelloJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);\n\n    /**\n     * <p>\n     * Empty constructor for job initialization\n     * </p>\n     * <p>\n     * Quartz requires a public empty constructor so that the scheduler can\n     * instantiate the class whenever it needs.\n     * </p>\n     */\n    public HelloJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with the\n     * <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n\n        // Say Hello to the World and display the date/time\n        _log.info(\"Hello World! - \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/JdbcQuartzDerbyUtilities.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\n\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.math.BigDecimal;\nimport java.nio.file.FileSystems;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.quartz.utils.ConnectionProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic final class JdbcQuartzDerbyUtilities {\n\n    private static final Logger LOG = LoggerFactory\n            .getLogger(JdbcQuartzDerbyUtilities.class);\n\n    private static final String DATABASE_DRIVER_CLASS = \"org.apache.derby.jdbc.ClientDriver\";\n    public static final String DATABASE_PORT = System.getProperty(\"test.databasePort\", \"1527\");;\n    public static final String DATABASE_CONNECTION_PREFIX;\n\n    private static final List<String> DATABASE_SETUP_STATEMENTS;\n    private static final List<String> DATABASE_TEARDOWN_STATEMENTS;\n    private static final String DERBY_DIRECTORY;\n\n    private final static Properties PROPS = new Properties();\n\n    static {\n        String derbyDirectory;\n        if (System.getProperty(\"buildDirectory\") != null) {\n            // running the tests from maven, the db will be stored in target/\n            derbyDirectory = System.getProperty(\"buildDirectory\");\n        } else if (System.getProperty(\"org.gradle.internal.worker.tmpdir\") != null) {\n            derbyDirectory = System.getProperty(\"org.gradle.internal.worker.tmpdir\");\n        } else {\n            derbyDirectory = System.getProperty(\"java.io.tmpdir\");\n        }\n\n        if(derbyDirectory.endsWith(\":\")) {\n            derbyDirectory = derbyDirectory.substring(0, derbyDirectory.length() - 1);\n        }\n        if(!derbyDirectory.endsWith(\"/\") && !derbyDirectory.endsWith(\"\\\\\")) {\n            derbyDirectory = derbyDirectory + FileSystems.getDefault().getSeparator();\n        }\n        derbyDirectory = derbyDirectory + \"quartzTestDB_\" + System.nanoTime();\n        DERBY_DIRECTORY = derbyDirectory;\n\n        LOG.info(\"The test db will be stored in \" + derbyDirectory);\n\n        DATABASE_CONNECTION_PREFIX = \"jdbc:derby://localhost:\" + DATABASE_PORT + \"/\"\n                + DERBY_DIRECTORY + \";create=true\";\n\n    \tPROPS.setProperty(\"user\",\"quartz\");\n    \tPROPS.setProperty(\"password\",\"quartz\");\n    \t\n    \t\n        try {\n            Class.forName(DATABASE_DRIVER_CLASS).newInstance();\n        } catch (ClassNotFoundException e) {\n            throw new AssertionError(e);\n        } catch (InstantiationException e) {\n            throw new AssertionError(e);\n        } catch (IllegalAccessException e) {\n            throw new AssertionError(e);\n        }\n\n        List<String> setup = new ArrayList<String>();\n        String setupScript;\n        try {\n            InputStream setupStream = DerbyConnectionProvider.class\n                    .getClassLoader().getResourceAsStream(\"org/quartz/impl/jdbcjobstore/tables_derby.sql\");\n            try {\n                BufferedReader r = new BufferedReader(new InputStreamReader(setupStream, \"US-ASCII\"));\n                StringBuilder sb = new StringBuilder();\n                while (true) {\n                    String line = r.readLine();\n                    if (line == null) {\n                        break;\n                    } else if (!line.startsWith(\"--\")) {\n                        sb.append(line).append(\"\\n\");\n                    }\n                }\n                setupScript = sb.toString();\n            } finally {\n                setupStream.close();\n            }\n        } catch (IOException e) {\n            throw new AssertionError(e);\n        }\n\n        for (String command : setupScript.split(\";\")) {\n            if (!command.matches(\"\\\\s*\")) {\n                setup.add(command);\n            }\n        }\n        DATABASE_SETUP_STATEMENTS = setup;\n        \n        \n        List<String> tearDown = new ArrayList<String>();\n        String tearDownScript;\n        try {\n            InputStream tearDownStream = DerbyConnectionProvider.class\n                    .getClassLoader().getResourceAsStream(\"tables_derby_drop.sql\");\n            try {\n                BufferedReader r = new BufferedReader(new InputStreamReader(tearDownStream, \"US-ASCII\"));\n                StringBuilder sb = new StringBuilder();\n                while (true) {\n                    String line = r.readLine();\n                    if (line == null) {\n                        break;\n                    } else if (!line.startsWith(\"--\")) {\n                        sb.append(line).append(\"\\n\");\n                    }\n                }\n                tearDownScript = sb.toString();\n            } finally {\n                tearDownStream.close();\n            }\n        } catch (IOException e) {\n            throw new AssertionError(e);\n        }\n\n        for (String command : tearDownScript.split(\";\")) {\n            if (!command.matches(\"\\\\s*\")) {\n            \ttearDown.add(command);\n            }\n        }\n        DATABASE_TEARDOWN_STATEMENTS = tearDown;\n        \n        \n    }\n\n    public static void createDatabase() throws SQLException {\n\n        File derbyDirectory = new File(DERBY_DIRECTORY);\n        delete(derbyDirectory);\n\n    \tConnection conn = DriverManager.getConnection(DATABASE_CONNECTION_PREFIX ,PROPS);\n        try {\n            Statement statement = conn.createStatement();\n            for (String command : DATABASE_SETUP_STATEMENTS) {\n                statement.addBatch(command);\n            }\n            statement.executeBatch();\n        }\n        finally {\n            conn.close();\n        }\n    }\n\n    \n\tpublic static int triggersInAcquiredState() throws SQLException {\n\t\tint triggersInAcquiredState = 0;\n\t\tConnection conn = DriverManager.getConnection(DATABASE_CONNECTION_PREFIX, PROPS);\n\t\ttry {\n\t\t\tStatement statement = conn.createStatement();\n\t\t\tResultSet result = statement.executeQuery(\"SELECT count( * ) FROM QRTZ_TRIGGERS WHERE TRIGGER_STATE = 'ACQUIRED' \");\n\t\t\twhile (result.next()) { \n\t\t\t\ttriggersInAcquiredState = result.getInt(1);\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.close();\n\t\t}\n\t\treturn triggersInAcquiredState;\n\t}\n    \n\t\n\tpublic static BigDecimal timesTriggered(String triggerName,String triggerGroup) throws SQLException {\n\t\tBigDecimal timesTriggered = BigDecimal.ZERO;\n\t\tConnection conn = DriverManager.getConnection(DATABASE_CONNECTION_PREFIX, PROPS);\n\t\ttry {\n\t\t\tPreparedStatement ps = conn.prepareStatement(\"SELECT TIMES_TRIGGERED FROM QRTZ_SIMPLE_TRIGGERS WHERE TRIGGER_NAME = ? AND TRIGGER_GROUP = ? \");\n\t\t\tps.setString(1, triggerName);\n\t\t\tps.setString(2, triggerGroup);\n\t\t\tResultSet result = ps.executeQuery();\n\t\t\tresult.next(); \n\t\t\ttimesTriggered = result.getBigDecimal(1);\n\t\t} finally {\n\t\t\tconn.close();\n\t\t}\n\t\treturn timesTriggered;\n\t}\n\t\n    public static void destroyDatabase() throws SQLException {\n    \tConnection conn = DriverManager.getConnection(DATABASE_CONNECTION_PREFIX ,PROPS);\n        try {\n            Statement statement = conn.createStatement();\n            for (String command : DATABASE_TEARDOWN_STATEMENTS) {\n                statement.addBatch(command);\n            }\n            statement.executeBatch();\n        }\n        finally {\n            conn.close();\n        }\n\n        File derbyDirectory = new File(DERBY_DIRECTORY);\n        delete(derbyDirectory);\n    }\n\n    static class DerbyConnectionProvider implements ConnectionProvider {\n\n\n\n        public Connection getConnection() throws SQLException {\n            return DriverManager.getConnection(DATABASE_CONNECTION_PREFIX , PROPS);\n        }\n\n        public void shutdown() throws SQLException {\n            // nothing to do\n        }\n\n\t\t@Override\n\t\tpublic void initialize() throws SQLException {\n\t\t\t// nothing to do\n\t\t}\n    }\n\n    private JdbcQuartzDerbyUtilities() {\n        // not instantiable\n    }\n\n    static void delete(File f)  {\n        if (f.isDirectory()) {\n            for (File c : f.listFiles())\n                delete(c);\n        }\n        if (!f.delete())\n            LOG.debug(\"Failed to delete file: \" + f +\" certainly because it does not exist yet\");\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/JobClassNotFoundExceptionErrorsTriggersTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.JobExecutionException;\nimport org.quartz.SchedulerException;\nimport org.quartz.simpl.CascadingClassLoadHelper;\n\nimport static org.quartz.impl.StdSchedulerFactory.PROP_SCHED_CLASS_LOAD_HELPER_CLASS;\n\npublic class JobClassNotFoundExceptionErrorsTriggersTest extends QuartzDerbyTestSupport {\n\n    private static final String BARRIER_KEY = \"BARRIER\";\n    \n    public static class BadJob implements Job {\n\n        public void execute(JobExecutionContext context) {\n            //no-op\n        }\n    }\n\n    public static class GoodJob implements Job {\n\n        @Override\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            try {\n                ((CyclicBarrier) context.getScheduler().getContext().get(BARRIER_KEY)).await(20, TimeUnit.SECONDS);\n            } catch (SchedulerException ex) {\n                throw new JobExecutionException(ex);\n            } catch (InterruptedException ex) {\n                throw new JobExecutionException(ex);\n            } catch (BrokenBarrierException ex) {\n                throw new JobExecutionException(ex);\n            } catch (TimeoutException ex) {\n                throw new JobExecutionException(ex);\n            }\n        }\n        \n    }\n\n    public static class SpecialClassLoadHelper extends CascadingClassLoadHelper {\n\n        @Override\n        public Class<?> loadClass(String name) throws ClassNotFoundException {\n            if (BadJob.class.getName().equals(name)) {\n                throw new ClassNotFoundException();\n            } else {\n                return super.loadClass(name);\n            }\n        }\n    }\n    \n    protected Properties createSchedulerProperties() {\n        Properties properties = super.createSchedulerProperties();\n        properties.put(PROP_SCHED_CLASS_LOAD_HELPER_CLASS, SpecialClassLoadHelper.class.getName());\n        return properties;\n    }\n\n    @Test\n    void testJobClassNotFoundDoesntBlock() throws Exception {\n        CyclicBarrier barrier = new CyclicBarrier(2);\n        scheduler.getContext().put(BARRIER_KEY, barrier);\n\n        JobDetail goodJob = JobBuilder.newJob(GoodJob.class).withIdentity(\"good\").build();\n        JobDetail badJob = JobBuilder.newJob(BadJob.class).withIdentity(\"bad\").build();\n\n        long now = System.currentTimeMillis();\n        Trigger goodTrigger = TriggerBuilder.newTrigger().withIdentity(\"good\").forJob(goodJob)\n                .startAt(new Date(now + 1))\n                .build();\n        \n        Trigger badTrigger = TriggerBuilder.newTrigger().withIdentity(\"bad\").forJob(badJob)\n                .startAt(new Date(now))\n                .build();\n\n        Map<JobDetail, Set<? extends Trigger>> toSchedule = new HashMap<JobDetail, Set<? extends Trigger>>();\n        toSchedule.put(badJob, Collections.singleton(badTrigger));\n        toSchedule.put(goodJob, Collections.singleton(goodTrigger));\n        scheduler.scheduleJobs(toSchedule, true);\n\n        barrier.await(20, TimeUnit.SECONDS);\n        \n        assertThat(scheduler.getTriggerState(badTrigger.getKey()), is(Trigger.TriggerState.ERROR));\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/JobDataMapStorageTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\n\nimport org.quartz.*;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\nimport static org.quartz.TriggerKey.triggerKey;\n\n/**\n * Created by zemian on 10/25/16.\n */\npublic class JobDataMapStorageTest extends QuartzDerbyTestSupport {\n    @Test\n    void testJobDataMapDirtyFlag() throws Exception {\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test\")\n                .usingJobData(\"jfoo\", \"bar\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test\")\n                .withSchedule(cronSchedule(\"0 0 0 * * ?\"))\n                .usingJobData(\"tfoo\", \"bar\")\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        JobDetail storedJobDetail = scheduler.getJobDetail(JobKey.jobKey(\"test\"));\n        JobDataMap storedJobMap = storedJobDetail.getJobDataMap();\n        assertThat(storedJobMap.isDirty(), is(false));\n\n        Trigger storedTrigger = scheduler.getTrigger(triggerKey(\"test\"));\n        JobDataMap storedTriggerMap = storedTrigger.getJobDataMap();\n        assertThat(storedTriggerMap.isDirty(), is(false));\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QTZ179_TriggerLostAfterDbRestart_Test.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobDetail;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.Trigger;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Properties;\n\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\npublic class QTZ179_TriggerLostAfterDbRestart_Test extends QuartzDerbyTestSupport {\n\n    private static final long DURATION_OF_FIRST_SCHEDULING = 9L;\n    private static final long DURATION_OF_NETWORK_FAILURE = 10L;\n    private static final long DURATION_OF_SECOND_SCHEDULING = 10L;\n    private static final Logger LOG = LoggerFactory.getLogger(QTZ179_TriggerLostAfterDbRestart_Test.class);\n    private static final int INTERVAL_IN_SECONDS = 3;\n    private static Trigger trigger1_1;\n    private static Trigger trigger2_1;\n    private static Trigger trigger1_2;\n    private static Trigger trigger2_2;\n\n    @Override\n    protected Properties createSchedulerProperties() {\n        Properties properties = new Properties();\n        properties.put(\"org.quartz.scheduler.instanceName\", \"TestScheduler\");\n        properties.put(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\", \"true\");\n        properties.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        properties.put(\"org.quartz.threadPool.threadCount\", \"12\");\n        properties.put(\"org.quartz.threadPool.threadPriority\", \"5\");\n        properties.put(\"org.quartz.jobStore.misfireThreshold\", \"10000\");\n        properties.put(\"org.quartz.jobStore.class\", \"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n        properties.put(\"org.quartz.jobStore.driverDelegateClass\", \"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\n        properties.put(\"org.quartz.jobStore.useProperties\", \"true\");\n        properties.put(\"org.quartz.jobStore.dataSource\", \"myDS\");\n        properties.put(\"org.quartz.jobStore.tablePrefix\", \"QRTZ_\");\n        properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\n        properties.put(\"org.quartz.dataSource.myDS.driver\", \"org.apache.derby.jdbc.ClientDriver\");\n        properties.put(\"org.quartz.dataSource.myDS.URL\", JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX);\n        properties.put(\"org.quartz.dataSource.myDS.user\", \"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.password\", \"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.maxConnections\", \"5\");\n        return properties;\n    }\n\n    @Override\n    protected void afterSchedulerInit() throws Exception {\n        LOG.info(\"------- Scheduling Job  -------------------\");\n\n        // define the jobs and tie them to our HelloJob class\n        JobDetail job1_1 = newJob(HelloJob.class).withIdentity(\"job1\", \"group1\").build();\n        JobDetail job2_1 = newJob(HelloJob.class).withIdentity(\"job2\", \"group1\").build();\n        JobDetail job1_2 = newJob(HelloJob.class).withIdentity(\"job1\", \"group2\").build();\n        JobDetail job2_2 = newJob(HelloJob.class).withIdentity(\"job2\", \"group2\").build();\n\n        trigger1_1 = newTrigger()\n                .withIdentity(\"job1\", \"group1\")\n                .startNow()\n                .withSchedule(\n                        SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(INTERVAL_IN_SECONDS)\n                                .repeatForever())\n                .build();\n        trigger2_1 = newTrigger()\n                .withIdentity(\"job2\", \"group1\")\n                .startNow()\n                .withSchedule(\n                        SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(INTERVAL_IN_SECONDS)\n                                .repeatForever())\n                .build();\n        trigger1_2 = newTrigger()\n                .withIdentity(\"job1\", \"group2\")\n                .startNow()\n                .withSchedule(\n                        SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(INTERVAL_IN_SECONDS)\n                                .repeatForever())\n                .build();\n        trigger2_2 = newTrigger()\n                .withIdentity(\"job2\", \"group2\")\n                .startNow()\n                .withSchedule(\n                        SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(INTERVAL_IN_SECONDS)\n                                .repeatForever())\n                .build();\n\n        Trigger[] triggers = new Trigger[]{trigger1_1, trigger1_2, trigger2_1, trigger2_2};\n        JobDetail[] jobDetails = new JobDetail[]{job1_1, job1_2, job2_1, job2_2};\n        for (int i = 0; i < triggers.length; i++) {\n            JobDetail job = jobDetails[i];\n            Trigger trigger = triggers[i];\n            if (scheduler.checkExists(job.getKey())) {\n                // the job already exists in jdbcjobstore; let's reschedule it\n                scheduler.rescheduleJob(trigger.getKey(), trigger);\n            } else {\n                scheduler.scheduleJob(job, trigger);\n            }\n        }\n\n        // Start up the scheduler (nothing can actually run until the\n        // scheduler has been started)\n        scheduler.start();\n    }\n\n    @Test\n    public void checkAll4TriggersStillRunningTest() throws Exception {\n\n        LOG.info(\"------- Scheduler Started -----------------\");\n\n        // wait long enough so that the scheduler as an opportunity to\n        // run the job!\n        try {\n            Thread.sleep(DURATION_OF_FIRST_SCHEDULING * 1000L);\n        } catch (Exception e) {\n        }\n\n        //there should be maximum 1 trigger in acquired state\n        if (JdbcQuartzDerbyUtilities.triggersInAcquiredState() > 1) {\n            fail(\"There should not be more than 1 trigger in ACQUIRED state in the DB.\");\n        }\n\n        // Shutting down and starting up again the database to simulate a\n        // network error\n        try {\n            LOG.info(\"------- Shutting down database ! -----------------\");\n            derbyServer.shutdown();\n            Thread.sleep(DURATION_OF_NETWORK_FAILURE * 1000L);\n            derbyServer.start(null);\n            LOG.info(\"------- Database back online ! -----------------\");\n            Thread.sleep(DURATION_OF_SECOND_SCHEDULING * 1000L);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        int triggersInAcquiredState = JdbcQuartzDerbyUtilities.triggersInAcquiredState();\n        assertFalse(triggersInAcquiredState > 1, \"There should not be more than 1 trigger in ACQUIRED state in the DB, but found \" + triggersInAcquiredState);\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QTZ283_IgnoreMisfirePolicyJdbcStore_Test.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DateBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.SimpleTrigger;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.math.BigDecimal;\nimport java.sql.SQLException;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.not;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\npublic class QTZ283_IgnoreMisfirePolicyJdbcStore_Test extends QuartzDerbyTestSupport {\n\n  private static final long DURATION_OF_FIRST_SCHEDULING = 10L;\n  private static final Logger LOG = LoggerFactory.getLogger(QTZ283_IgnoreMisfirePolicyJdbcStore_Test.class);\n  private static final int INTERVAL_IN_SECONDS = 5;\n\n  @Override\n  protected Properties createSchedulerProperties() {\n    Properties properties = new Properties();\n    properties.put(\"org.quartz.scheduler.instanceName\", \"TestScheduler\");\n    properties.put(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n    properties.put(\"org.quartz.scheduler.skipUpdateCheck\", \"true\");\n    properties.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n    properties.put(\"org.quartz.threadPool.threadCount\", \"12\");\n    properties.put(\"org.quartz.threadPool.threadPriority\", \"5\");\n    properties.put(\"org.quartz.jobStore.misfireThreshold\", \"10000\");\n    properties.put(\"org.quartz.jobStore.class\", \"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n    properties.put(\"org.quartz.jobStore.driverDelegateClass\", \"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\n    properties.put(\"org.quartz.jobStore.useProperties\", \"true\");\n    properties.put(\"org.quartz.jobStore.dataSource\", \"myDS\");\n    properties.put(\"org.quartz.jobStore.tablePrefix\", \"QRTZ_\");\n    properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\n    properties.put(\"org.quartz.dataSource.myDS.driver\", \"org.apache.derby.jdbc.ClientDriver\");\n    properties.put(\"org.quartz.dataSource.myDS.URL\", JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX);\n    properties.put(\"org.quartz.dataSource.myDS.user\", \"quartz\");\n    properties.put(\"org.quartz.dataSource.myDS.password\", \"quartz\");\n    properties.put(\"org.quartz.dataSource.myDS.maxConnections\", \"5\");\n    return properties;\n  }\n\n  @Override\n \tprotected void afterSchedulerInit() throws Exception {\n\n\n    LOG.info(\"------- Scheduling Job  -------------------\");\n\n    // define the jobs and tie them to our HelloJob class\n    JobDetail job1 = newJob(HelloJob.class).withIdentity(\"job1\", \"group1\").build();\n\n    // trigger should have started the even minute before now\n    // due to its ignore policy, it will be triggered\n    Date startTime1 = DateBuilder.evenMinuteDateBefore(null);\n    SimpleTrigger oldtriggerMisfirePolicyIgnore = newTrigger()\n        .withIdentity(\"trigger1\", \"group1\")\n        .startAt(startTime1)\n        .withSchedule(\n            simpleSchedule().withIntervalInSeconds(INTERVAL_IN_SECONDS)\n                .repeatForever()\n                .withMisfireHandlingInstructionIgnoreMisfires())\n        .build();\n\n    if (scheduler.checkExists(job1.getKey())) {\n      // the job already exists in jdbcjobstore; let's reschedule it\n      scheduler.rescheduleJob(oldtriggerMisfirePolicyIgnore.getKey(), oldtriggerMisfirePolicyIgnore);\n    } else {\n      scheduler.scheduleJob(job1, oldtriggerMisfirePolicyIgnore);\n    }\n\n    // Start up the scheduler (nothing can actually run until the\n    // scheduler has been started)\n    scheduler.start();\n\n    LOG.info(\"------- Scheduler Started -----------------\");\n\n    // wait long enough so that the scheduler as an opportunity to\n    // run the job!\n    try {\n      Thread.sleep(DURATION_OF_FIRST_SCHEDULING * 1000L);\n    } catch (Exception e) {\n      e.printStackTrace();\n    }\n  }\n\n  @Test\n  public void checkOldTriggerGetsFired() throws SQLException {\n    BigDecimal misfirePolicyIgnoreTimesTriggered = JdbcQuartzDerbyUtilities.timesTriggered(\"trigger1\", \"group1\");\n    assertThat(\"The old trigger has never been fired, even if the policy is ignore\", misfirePolicyIgnoreTimesTriggered,\n        not(equalTo(BigDecimal.ZERO)));\n  }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QTZ336_MissSchedulingChangeSignalTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.integrations.tests;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.simpl.RAMJobStore;\nimport org.quartz.spi.OperableTrigger;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Integration test for reproducing QTZ-336 where we don't check for the scheduling change signal.\n */\n@Disabled /* ignoring now since the bug is years ago fixed, and the test takes a full minute! */\nclass QTZ336_MissSchedulingChangeSignalTest {\n    private static final Logger LOG = LoggerFactory.getLogger(QTZ336_MissSchedulingChangeSignalTest.class);\n\t\n    @Test\n    void simpleScheduleAlwaysFiredUnder20s() throws Exception {\n        Properties properties = new Properties();\n        InputStream propertiesIs = getClass().getResourceAsStream(\"/org/quartz/quartz.properties\");\n        try {\n            properties.load(propertiesIs);\n        } finally {\n            propertiesIs.close();\n        }\n        properties.setProperty(\"org.quartz.scheduler.name\", \"QTZ336_MissSchedulingChangeSignalTest.simpleScheduleAlwaysFiredUnder20s\");\n        properties.setProperty(\"org.quartz.scheduler.skipUpdateCheck\", \"true\");\n        // Use a custom RAMJobStore to produce context switches leading to the race condition\n        properties.setProperty(\"org.quartz.jobStore.class\", SlowRAMJobStore.class.getName());\n        SchedulerFactory sf = new StdSchedulerFactory(properties);\n        Scheduler sched = sf.getScheduler();\n\t\tLOG.info(\"------- Initialization Complete -----------\");\n\n\t\tLOG.info(\"------- Scheduling Job  -------------------\");\n\n        JobDetail job = newJob(CollectDurationBetweenFireTimesJob.class).withIdentity(\"job\", \"group\").build();\n\n        SimpleTrigger trigger = newTrigger()\n\t            .withIdentity(\"trigger1\", \"group1\")\n                .startAt(new Date(System.currentTimeMillis() + 1000))\n\t            .withSchedule(simpleSchedule()\n                .withIntervalInSeconds(1)\n\t            .repeatForever()\n\t            .withMisfireHandlingInstructionIgnoreMisfires())\n\t            .build();\n\n        sched.scheduleJob(job, trigger);\n\t        \n\t\t// Start up the scheduler (nothing can actually run until the\n\t\t// scheduler has been started)\n\t\tsched.start();\n\n\t\tLOG.info(\"------- Scheduler Started -----------------\");\n\t\t\n\n        // wait long enough so that the scheduler has an opportunity to\n        // run the job in theory around 50 times\n\t\ttry {\n            Thread.sleep(50000L);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n        List<Long> durationBetweenFireTimesInMillis = CollectDurationBetweenFireTimesJob.getDurations();\n        \n        assertFalse(durationBetweenFireTimesInMillis.isEmpty(), \"Job was not executed once!\");\n        \n        // Let's check that every call for around 1 second and not between 23 and 30 seconds\n        // which would be the case if the scheduling change signal were not checked\n        for (long durationInMillis : durationBetweenFireTimesInMillis) {\n            assertTrue(durationInMillis < 20000, \"Missed an execution with one duration being between two fires: \" + durationInMillis + \" (all: \"\n                                + durationBetweenFireTimesInMillis + \")\");\n        }\n\t}\n\n    /**\n     * A simple job for collecting fire times in order to check that we did not miss one call, for having the race\n     * condition the job must be real quick and not allowing concurrent executions.\n     */\n    @DisallowConcurrentExecution\n    public static class CollectDurationBetweenFireTimesJob implements Job {\n        private static final Logger log = LoggerFactory.getLogger(CollectDurationBetweenFireTimesJob.class);\n        private static final List<Long> durationBetweenFireTimes = Collections.synchronizedList(new ArrayList<Long>());\n        private static Long lastFireTime = null;\n\n        public void execute(JobExecutionContext context) throws JobExecutionException {\n            Date now = new Date();\n            log.info(\"Fire time: \" + now);\n            if (lastFireTime != null) {\n                durationBetweenFireTimes.add(now.getTime() - lastFireTime);\n            }\n            lastFireTime = now.getTime();\n        }\n\n        /**\n         * Retrieves the durations between fire times.\n         * \n         * @return the durations in millis as an immutable list.\n         */\n        public static List<Long> getDurations() {\n            synchronized (durationBetweenFireTimes) {\n              return Collections.unmodifiableList(new ArrayList<Long>(durationBetweenFireTimes));\n            }\n        }\n\n    }\n\n    /**\n     * Custom RAMJobStore for producing context switches.\n     */\n    public static class SlowRAMJobStore extends RAMJobStore {\n        @Override\n        public List<OperableTrigger> acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) {\n            List<OperableTrigger> nextTriggers = super.acquireNextTriggers(noLaterThan, maxCount, timeWindow);\n            try {\n                // Wait just a bit for hopefully having a context switch leading to the race condition\n                Thread.sleep(10);\n            } catch (InterruptedException e) {\n            }\n            return nextTriggers;\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzDatabasePauseAndResumeTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDetail;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.not;\n\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\n/**\n * Created by zemian on 10/25/16.\n */\npublic class QuartzDatabasePauseAndResumeTest extends QuartzDerbyTestSupport {\n\n    @Test\n    void testPauseAndResumeTriggers() throws Exception {\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test_1\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test_1\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_1\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_1\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_1\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n    @Test\n    void testResumeTriggersBeforeAddJob() throws Exception {\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test_2\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test_2\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_2\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_2\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_2\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n    @Test\n    void testPauseAndResumeJobs() throws Exception {\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test_3\", \"abc\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test_3\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_3\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_3\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_3\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n\n    @Test\n    void testResumeJobsBeforeAddJobs() throws Exception {\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test_4\", \"abc\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test_4\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_4\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_4\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test_4\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzDatabaseSimplePropertiesTest.java",
    "content": "/* \n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport java.math.BigDecimal;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.quartz.JobDetail;\nimport org.quartz.ScheduleBuilder;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerPersistenceDelegateSupport;\nimport org.quartz.impl.jdbcjobstore.SimplePropertiesTriggerProperties;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\nimport org.quartz.spi.MutableTrigger;\nimport org.quartz.spi.OperableTrigger;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.samePropertyValuesAs;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\npublic class QuartzDatabaseSimplePropertiesTest extends QuartzDerbyTestSupport {\n\n\t@Override\n\tprotected Properties createSchedulerProperties() {\n\t\tProperties defaultSchedulerProperties = super.createSchedulerProperties();\n\t\tdefaultSchedulerProperties.put(\n\t\t\t\t\"org.quartz.jobStore.driverDelegateInitString\",\n\t\t\t\t\"triggerPersistenceDelegateClasses=\" + TestSimplePropertiesTriggerPersistenceDelegate.class.getName()\n\t\t);\n\t\treturn defaultSchedulerProperties;\n\t}\n\n\t@Test\n\tpublic void insertAndLoadProperties() throws SchedulerException {\n\t\tTriggerKey triggerKey = new TriggerKey(\"test\");\n\t\tTestTriggerImpl trigger = (TestTriggerImpl) newTrigger()\n\t\t\t\t.withIdentity(triggerKey)\n\t\t\t\t.withSchedule(new TestTriggerScheduleBuilder())\n\t\t\t\t.build();\n\n\t\tSimplePropertiesTriggerProperties insertedProperties = new SimplePropertiesTriggerProperties();\n\t\tinsertedProperties.setString1(\"\");\n\t\tinsertedProperties.setString2(null);\n\t\tinsertedProperties.setString3(\"test-string\");\n\t\tinsertedProperties.setInt1(Integer.MIN_VALUE);\n\t\tinsertedProperties.setInt2(Integer.MAX_VALUE);\n\t\tinsertedProperties.setLong1(Long.MIN_VALUE);\n\t\tinsertedProperties.setLong2(Long.MAX_VALUE);\n\t\tinsertedProperties.setDecimal1(new BigDecimal(\"0.0000\"));\n\t\tinsertedProperties.setDecimal2(new BigDecimal(\"-10.0000\"));\n\t\tinsertedProperties.setBoolean1(true);\n\t\tinsertedProperties.setBoolean2(false);\n\t\ttrigger.setAdditionalProperties(insertedProperties);\n\n\t\tJobDetail job = newJob(HelloJob.class).withIdentity(\"test\").build();\n\n\t\tscheduler.scheduleJob(job, trigger);\n\t\tTestTriggerImpl loadedTrigger = ((TestTriggerImpl) scheduler.getTrigger(triggerKey));\n\n\t\tSimplePropertiesTriggerProperties loadedProperties = loadedTrigger.getAdditionalProperties();\n\t\tassertThat(loadedProperties, samePropertyValuesAs(insertedProperties));\n\t}\n\n\tpublic static class TestTriggerImpl extends SimpleTriggerImpl {\n\t\tprivate SimplePropertiesTriggerProperties additionalProperties;\n\n\t\t@Override\n\t\tpublic boolean hasAdditionalProperties() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic SimplePropertiesTriggerProperties getAdditionalProperties() {\n\t\t\treturn additionalProperties;\n\t\t}\n\n\t\tpublic void setAdditionalProperties(SimplePropertiesTriggerProperties additionalProperties) {\n\t\t\tthis.additionalProperties = additionalProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic ScheduleBuilder<SimpleTrigger> getScheduleBuilder() {\n\t\t\treturn new TestTriggerScheduleBuilder();\n\t\t}\n\t}\n\n\tpublic static class TestTriggerScheduleBuilder extends ScheduleBuilder<SimpleTrigger> {\n\n\t\t@Override\n\t\tprotected MutableTrigger build() {\n\t\t\treturn new TestTriggerImpl();\n\t\t}\n\t}\n\n\tpublic static class TestSimplePropertiesTriggerPersistenceDelegate extends\n\t\t\tSimplePropertiesTriggerPersistenceDelegateSupport {\n\n\t\t@Override\n\t\tpublic boolean canHandleTriggerType(OperableTrigger trigger) {\n\t\t\treturn trigger instanceof TestTriggerImpl;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getHandledTriggerTypeDiscriminator() {\n\t\t\treturn \"TEST\";\n\t\t}\n\n\t\t@Override\n\t\tprotected SimplePropertiesTriggerProperties getTriggerProperties(OperableTrigger trigger) {\n\t\t\treturn ((TestTriggerImpl) trigger).getAdditionalProperties();\n\t\t}\n\n\t\t@Override\n\t\tprotected TriggerPropertyBundle getTriggerPropertyBundle(SimplePropertiesTriggerProperties properties) {\n\t\t\treturn new TriggerPropertyBundle(\n\t\t\t\t\tnew TestTriggerScheduleBuilder(),\n\t\t\t\t\tnew String[] {\"additionalProperties\"},\n\t\t\t\t\tnew Object[] {properties}\n\t\t\t);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzDerbyCronTriggerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\npackage org.quartz.integrations.tests;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\nimport static org.hamcrest.core.Is.is;\nimport static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;\n\n\nimport org.quartz.*;\nimport static org.quartz.integrations.tests.TrackingJob.SCHEDULED_TIMES_KEY;\n\n/**\n * A integration test for Quartz Database Scheduler with Cron Trigger.\n * @author Zemian Deng\n */\npublic class QuartzDerbyCronTriggerTest extends QuartzDerbyTestSupport {\n    @Test\n    void testCronRepeatCount() throws Exception {\n        CronTrigger trigger = TriggerBuilder.newTrigger()\n                .withIdentity(\"test\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\"))\n                .build();\n        List<Long> scheduledTimes = Collections.synchronizedList(new LinkedList<Long>());\n        scheduler.getContext().put(SCHEDULED_TIMES_KEY, scheduledTimes);\n        JobDetail jobDetail = JobBuilder.newJob(TrackingJob.class).withIdentity(\"test\").build();\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        for (int i = 0; i < 20 && scheduledTimes.size() < 3; i++) {\n          Thread.sleep(500);\n        }\n        assertThat(scheduledTimes, hasSize(greaterThanOrEqualTo(3)));\n        \n        Long[] times = scheduledTimes.toArray(new Long[scheduledTimes.size()]);\n        long baseline = times[0];\n        assertThat(baseline % 1000, is(0L));\n        for (int i = 1; i < times.length; i++) {\n          assertThat(times[i], is(baseline + TimeUnit.SECONDS.toMillis(i)));\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzDerbyTestSupport.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\npackage org.quartz.integrations.tests;\n\nimport org.apache.derby.drda.NetworkServerControl;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\nimport java.io.PrintWriter;\nimport java.net.InetAddress;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\n/**\n * A base class to support database (DERBY) scheduler integration testing. Each test will have a fresh\n * scheduler created and started, and it will auto shutdown upon each test run. The database will\n * be created with schema before class and destroy after class test.\n *\n * @author Zemian Deng\n */\npublic class QuartzDerbyTestSupport extends QuartzMemoryTestSupport {\n    protected static final Logger LOG = LoggerFactory.getLogger(QuartzDerbyTestSupport.class);\n    protected static NetworkServerControl derbyServer;\n\n    @BeforeAll\n    public static void initialize() throws Exception {\n        LOG.info(\"Starting DERBY database.\");\n        InetAddress localhost = InetAddress.getByName(\"localhost\");\n        int portNum = Integer.parseInt(JdbcQuartzDerbyUtilities.DATABASE_PORT);\n        derbyServer = new NetworkServerControl(localhost, portNum);\n        derbyServer.start(new PrintWriter(System.out));\n        int tries = 0;\n        while (tries < 5) {\n            try {\n                Thread.sleep(500);\n                derbyServer.ping();\n                break;\n            } catch (Exception e) {\n                tries++;\n            }\n        }\n        if (tries == 5) {\n            throw new Exception(\"Failed to start Derby!\");\n        }\n        LOG.info(\"Database started\");\n        try {\n            LOG.info(\"Creating Database tables for Quartz.\");\n            JdbcQuartzDerbyUtilities.createDatabase();\n            LOG.info(\"Database tables created.\");\n        } catch (SQLException e) {\n            throw new Exception(\"Failed to create Quartz tables.\", e);\n        }\n    }\n\n    @AfterAll\n    public static void shutdownDb() throws Exception {\n        try {\n            LOG.info(\"Destroying Database.\");\n            JdbcQuartzDerbyUtilities.destroyDatabase();\n            LOG.info(\"Database destroyed.\");\n        } catch (SQLException e) {\n            e.printStackTrace();\n            e.getNextException().printStackTrace();\n            throw new AssertionError(e);\n        }\n\n        derbyServer.shutdown();\n        LOG.info(\"Database shutdown.\");\n    }\n\n    protected Properties createSchedulerProperties() {\n        Properties properties = new Properties();\n        properties.put(\"org.quartz.scheduler.instanceName\",\"TestScheduler\");\n        properties.put(\"org.quartz.scheduler.instanceId\",\"AUTO\");\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\",\"true\");\n        properties.put(\"org.quartz.threadPool.class\",\"org.quartz.simpl.SimpleThreadPool\");\n        properties.put(\"org.quartz.threadPool.threadCount\",\"12\");\n        properties.put(\"org.quartz.threadPool.threadPriority\",\"5\");\n        properties.put(\"org.quartz.jobStore.misfireThreshold\",\"10000\");\n        properties.put(\"org.quartz.jobStore.class\",\"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n        properties.put(\"org.quartz.jobStore.driverDelegateClass\",\"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\n        properties.put(\"org.quartz.jobStore.useProperties\",\"true\");\n        properties.put(\"org.quartz.jobStore.dataSource\",\"myDS\");\n        properties.put(\"org.quartz.jobStore.tablePrefix\",\"QRTZ_\");\n        properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\n        properties.put(\"org.quartz.dataSource.myDS.driver\", \"org.apache.derby.jdbc.ClientDriver\");\n        properties.put(\"org.quartz.dataSource.myDS.URL\",JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX);\n        properties.put(\"org.quartz.dataSource.myDS.user\",\"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.password\",\"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.maxConnections\",\"5\");\n        return properties;\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzMSSQLDatabaseCronTriggerTest.java",
    "content": "/* \n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.integrations.tests;\nimport java.util.Collections;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.*;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\nimport static org.hamcrest.core.Is.is;\nimport static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;\nimport static org.quartz.integrations.tests.TrackingJob.SCHEDULED_TIMES_KEY;\n/**\n * A integration test for Quartz MSSQL Database Scheduler with Cron Trigger.\n * \n * @author Arnaud Mergey\n */\npublic class QuartzMSSQLDatabaseCronTriggerTest extends QuartzMSSQLTestSupport {\n\t@Test\n    void testCronRepeatCount() throws Exception {\n        CronTrigger trigger = TriggerBuilder.newTrigger()\n                .withIdentity(\"test\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\"))\n                .build();\n        List<Long> scheduledTimes = Collections.synchronizedList(new LinkedList<Long>());\n        scheduler.getContext().put(SCHEDULED_TIMES_KEY, scheduledTimes);\n        JobDetail jobDetail = JobBuilder.newJob(TrackingJob.class).withIdentity(\"test\").build();\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        for (int i = 0; i < 20 && scheduledTimes.size() < 3; i++) {\n          Thread.sleep(500);\n        }\n        assertThat(scheduledTimes, hasSize(greaterThanOrEqualTo(3)));\n        \n        Long[] times = scheduledTimes.toArray(new Long[scheduledTimes.size()]);\n        long baseline = times[0];\n        assertThat(baseline % 1000, is(0L));\n        for (int i = 1; i < times.length; i++) {\n          assertThat(times[i], is(baseline + TimeUnit.SECONDS.toMillis(i)));\n        }\n    }\n}"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzMSSQLTestSupport.java",
    "content": "/* \n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\npackage org.quartz.integrations.tests;\n\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.impl.jdbcjobstore.MSSQLDelegate;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A base class to support database (MSSQL) scheduler integration testing. Each\n * test will have a fresh scheduler created and started, and it will auto\n * shutdown upon each test run. The database will be created with schema before\n * class and destroy after class test.\n *\n * @author Arnaud Mergey\n */\npublic class QuartzMSSQLTestSupport extends QuartzMemoryTestSupport {\n    protected static final Logger LOG = LoggerFactory.getLogger(QuartzMSSQLTestSupport.class);\n    \n    private static final DatabaseType DATABASE_TYPE = DatabaseType.MSSQL;\n\n    @BeforeAll\n    public static void initialize() throws Exception {\n        try {\n            LOG.info(\"Creating Database tables for Quartz.\");\n            JdbcQuartzTestUtilities.createDatabase(DATABASE_TYPE.name(), DATABASE_TYPE);\n            LOG.info(\"Database tables created.\");\n        } catch (SQLException e) {\n            throw new Exception(\"Failed to create Quartz tables.\", e);\n        }\n    }\n\n    @AfterAll\n    public static void shutdownDb() throws Exception {\n        JdbcQuartzTestUtilities.shutdownDatabase(DATABASE_TYPE.name(),DATABASE_TYPE);\n        LOG.info(\"Database shutdown.\");\n    }\n\n    protected Properties createSchedulerProperties() {\n        Properties properties = new Properties();\n        properties.put(\"org.quartz.scheduler.instanceName\", \"TestScheduler\");\n        properties.put(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\", \"true\");\n        properties.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        properties.put(\"org.quartz.threadPool.threadCount\", \"12\");\n        properties.put(\"org.quartz.threadPool.threadPriority\", \"5\");\n        properties.put(\"org.quartz.jobStore.misfireThreshold\", \"10000\");\n        properties.put(\"org.quartz.jobStore.class\", \"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n        properties.put(\"org.quartz.jobStore.driverDelegateClass\", DATABASE_TYPE.getDelegateClassName());\n        properties.put(\"org.quartz.jobStore.useProperties\", \"true\");\n        properties.put(\"org.quartz.jobStore.dataSource\", DATABASE_TYPE.name());\n        properties.put(\"org.quartz.jobStore.tablePrefix\", \"QRTZ_\");\n        properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\n        return properties;\n    }\n}"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzMemoryCronTriggerTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\npackage org.quartz.integrations.tests;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\nimport static org.hamcrest.core.Is.is;\nimport static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;\n\n\nimport org.quartz.*;\nimport static org.quartz.integrations.tests.TrackingJob.SCHEDULED_TIMES_KEY;\n\n/**\n * A integration test for Quartz In-Memory Scheduler with Cron Trigger.\n * @author Zemian Deng\n */\npublic class QuartzMemoryCronTriggerTest extends QuartzMemoryTestSupport {\n    @Test\n    void testCronRepeatCount() throws Exception {\n        CronTrigger trigger = TriggerBuilder.newTrigger()\n                .withIdentity(\"test\")\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\"))\n                .build();\n        List<Long> scheduledTimes = Collections.synchronizedList(new LinkedList<Long>());\n        scheduler.getContext().put(SCHEDULED_TIMES_KEY, scheduledTimes);\n        JobDetail jobDetail = JobBuilder.newJob(TrackingJob.class).withIdentity(\"test\").build();\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        for (int i = 0; i < 20 && scheduledTimes.size() < 3; i++) {\n          Thread.sleep(500);\n        }\n        assertThat(scheduledTimes, hasSize(greaterThanOrEqualTo(3)));\n\n        Long[] times = scheduledTimes.toArray(new Long[scheduledTimes.size()]);\n        \n        long baseline = times[0];\n        assertThat(baseline % 1000, is(0L));\n        for (int i = 1; i < times.length; i++) {\n          assertThat(times[i], is(baseline + TimeUnit.SECONDS.toMillis(i)));\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzMemoryPauseAndResumeTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.impl.matchers.GroupMatcher;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.not;\n\n\nimport org.quartz.*;\nimport static org.quartz.CronScheduleBuilder.cronSchedule;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\nimport static org.quartz.TriggerKey.triggerKey;\n\n/**\n * Created by zemian on 10/25/16.\n */\npublic class QuartzMemoryPauseAndResumeTest extends QuartzMemoryTestSupport {\n\n    @Test\n    void testPauseAndResumeTriggers() throws Exception {\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n    @Test\n    void testResumeTriggersBeforeAddJob() throws Exception {\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeTriggers(GroupMatcher.triggerGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n    @Test\n    void testPauseAndResumeJobs() throws Exception {\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test\", \"abc\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n\n\n    @Test\n    void testResumeJobsBeforeAddJobs() throws Exception {\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n\n        JobDetail jobDetail = newJob(HelloJob.class)\n                .withIdentity(\"test\", \"abc\")\n                .build();\n\n        CronTrigger trigger = newTrigger()\n                .withIdentity(\"test\", \"abc\")\n                .withSchedule(cronSchedule(\"* * * * * ?\"))\n                .build();\n\n        scheduler.scheduleJob(jobDetail, trigger);\n\n        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n\n        scheduler.pauseJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.PAUSED));\n        assertThat(state, not(Trigger.TriggerState.NORMAL));\n\n        scheduler.resumeJobs(GroupMatcher.jobGroupEquals(\"abc\"));\n        state = scheduler.getTriggerState(TriggerKey.triggerKey(\"test\", \"abc\"));\n        assertThat(state, is(Trigger.TriggerState.NORMAL));\n        assertThat(state, not(Trigger.TriggerState.PAUSED));\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/QuartzMemoryTestSupport.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\npackage org.quartz.integrations.tests;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Properties;\n\n/**\n * A base class to support in-memory scheduler integration testing. Each test will have a fresh\n * scheduler created and started, and it will auto shutdown upon each test run.\n *\n * @author Zemian Deng\n */\npublic class QuartzMemoryTestSupport {\n    protected static final Logger LOG = LoggerFactory.getLogger(QuartzMemoryTestSupport.class);\n    protected Scheduler scheduler;\n\n    @BeforeEach\n    public void initSchedulerBeforeTest() throws Exception {\n        Properties properties = createSchedulerProperties();\n        SchedulerFactory sf = new StdSchedulerFactory(properties);\n        scheduler = sf.getScheduler();\n        afterSchedulerInit();\n    }\n\n    protected void afterSchedulerInit() throws Exception {\n        LOG.info(\"Scheduler starting.\");\n        scheduler.start();\n        LOG.info(\"Scheduler started.\");\n    }\n\n    protected Properties createSchedulerProperties() {\n        Properties properties = new Properties();\n        properties.put(\"org.quartz.scheduler.instanceName\",\"TestScheduler\");\n        properties.put(\"org.quartz.scheduler.instanceId\",\"AUTO\");\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\",\"true\");\n        properties.put(\"org.quartz.threadPool.class\",\"org.quartz.simpl.SimpleThreadPool\");\n        properties.put(\"org.quartz.threadPool.threadCount\",\"12\");\n        properties.put(\"org.quartz.threadPool.threadPriority\",\"5\");\n        properties.put(\"org.quartz.jobStore.misfireThreshold\",\"10000\");\n        return properties;\n    }\n\n    @AfterEach\n    public void initSchedulerAfterTest() throws Exception {\n        LOG.info(\"Scheduler shutting down.\");\n        scheduler.shutdown(true);\n        LOG.info(\"Scheduler shutdown complete.\");\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/StdRowLockSemaphoreTest.java",
    "content": "package org.quartz.integrations.tests;\n\nimport java.sql.Connection;\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport org.hamcrest.Matchers;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.jdbcjobstore.LockException;\nimport org.quartz.impl.jdbcjobstore.StdRowLockSemaphore;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class StdRowLockSemaphoreTest extends QuartzDerbyTestSupport {\n  static volatile boolean myLockInvoked = false;\n  static volatile int maxRetry = -1;\n  static volatile long retryPeriod = -1;\n  static CountDownLatch latch = new CountDownLatch(1);\n\n  public static class MyLock extends StdRowLockSemaphore {\n    @Override\n    protected void executeSQL(Connection conn, String lockName, String expandedSQL,\n        String expandedInsertSQL) throws LockException {\n      myLockInvoked = true;\n      maxRetry = getMaxRetry();\n      retryPeriod = getRetryPeriod();\n      super.executeSQL(conn, lockName, expandedSQL, expandedInsertSQL);\n      latch.countDown();\n    }\n  }\n\n  @Override\n  public void initSchedulerBeforeTest() throws Exception {\n    // Override to use initSchedulerBeforeTest(Properties) instead.\n  }\n\n  public void initSchedulerBeforeTest(Properties properties) throws Exception {\n    SchedulerFactory sf = new StdSchedulerFactory(properties);\n    scheduler = sf.getScheduler();\n    afterSchedulerInit();\n  }\n\n  Properties createDefaultProperties() {\n    Properties props = super.createSchedulerProperties();\n    props.setProperty(\"org.quartz.jobStore.lockHandler.class\", \"org.quartz.integrations.tests.StdRowLockSemaphoreTest$MyLock\");\n    props.setProperty(\"org.quartz.jobStore.acquireTriggersWithinLock\", \"true\");\n    return props;\n  }\n\n  Properties createMyLockProperties() {\n    Properties props = super.createSchedulerProperties();\n    props.setProperty(\"org.quartz.jobStore.lockHandler.class\", \"org.quartz.integrations.tests.StdRowLockSemaphoreTest$MyLock\");\n    props.setProperty(\"org.quartz.jobStore.lockHandler.maxRetry\", \"7\");\n    props.setProperty(\"org.quartz.jobStore.lockHandler.retryPeriod\", \"3000\");\n    props.setProperty(\"org.quartz.jobStore.acquireTriggersWithinLock\", \"true\");\n    return props;\n  }\n\n  @Test\n  void testDefaultStdRowLockSemaphore() throws Exception {\n    initSchedulerBeforeTest(createDefaultProperties());\n\n    JobDetail job1 = JobBuilder.newJob(HelloJob.class).withIdentity(\"job1\").\n        build();\n\n    HashSet<Trigger> triggers = new HashSet<>();\n    triggers.add(TriggerBuilder.newTrigger().forJob(job1)\n        .build());\n\n    scheduler.scheduleJob(job1, triggers, true);\n\n    latch.await(1L, TimeUnit.MINUTES);\n\n    assertThat(myLockInvoked, Matchers.is(true));\n    assertThat(maxRetry, Matchers.is(3));\n    assertThat(retryPeriod, Matchers.is(1000L));\n  }\n\n  @Test\n  void testCustomStdRowLockSemaphore() throws Exception {\n    initSchedulerBeforeTest(createMyLockProperties());\n\n    JobDetail job1 = JobBuilder.newJob(HelloJob.class).withIdentity(\"job1\").\n            build();\n\n    HashSet<Trigger> triggers = new HashSet<>();\n    triggers.add(TriggerBuilder.newTrigger().forJob(job1)\n        .build());\n\n    scheduler.scheduleJob(job1, triggers, true);\n\n    latch.await(1L, TimeUnit.MINUTES);\n\n    assertThat(myLockInvoked, Matchers.is(true));\n    assertThat(maxRetry, Matchers.is(7));\n    assertThat(retryPeriod, Matchers.is(3000L));\n  }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/integrations/tests/TrackingJob.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport java.util.List;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\n/**\n *\n * @author cdennis\n */\npublic class TrackingJob implements Job {\n    public static String SCHEDULED_TIMES_KEY = \"TrackingJob.ScheduledTimes\";\n    @Override\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n        try {\n            Scheduler scheduler = context.getScheduler();\n            List<Long> scheduledFires = (List<Long>)scheduler.getContext().get(SCHEDULED_TIMES_KEY);\n            scheduledFires.add(context.getScheduledFireTime().getTime());\n        } catch (SchedulerException e) {\n            throw new JobExecutionException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/simpl/PropertySettingJobFactoryTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.simpl;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.JobDataMap;\nimport org.quartz.SchedulerException;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n\n/**\n * Unit test for PropertySettingJobFactory.\n */\nclass PropertySettingJobFactoryTest  {\n    \n    private PropertySettingJobFactory factory;\n    \n    @BeforeEach\n    protected void setUp() throws Exception {\n        factory = new PropertySettingJobFactory();\n        factory.setThrowIfPropertyNotFound(true);    \n    }\n\n    @Test\n    void testSetBeanPropsPrimatives() throws SchedulerException {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"intValue\", Integer.valueOf(1));\n        jobDataMap.put(\"longValue\", Long.valueOf(2l));\n        jobDataMap.put(\"floatValue\", Float.valueOf(3.0f));\n        jobDataMap.put(\"doubleValue\", Double.valueOf(4.0));\n        jobDataMap.put(\"booleanValue\", Boolean.TRUE);\n        jobDataMap.put(\"shortValue\", Short.valueOf(((short)5)));\n        jobDataMap.put(\"charValue\", 'a');\n        jobDataMap.put(\"byteValue\", Byte.valueOf((byte)6));\n        jobDataMap.put(\"stringValue\", \"S1\");\n        jobDataMap.put(\"mapValue\", Collections.singletonMap(\"A\", \"B\"));\n        \n        TestBean myBean = new TestBean();\n        factory.setBeanProps(myBean, jobDataMap);\n        \n        assertEquals(1, myBean.getIntValue());\n        assertEquals(2l, myBean.getLongValue());\n        assertEquals(3.0f, myBean.getFloatValue(), 0.0001);\n        assertEquals(4.0, myBean.getDoubleValue(), 0.0001);\n        assertTrue(myBean.getBooleanValue());\n        assertEquals(5, myBean.getShortValue());\n        assertEquals('a', myBean.getCharValue());\n        assertEquals((byte)6, myBean.getByteValue());\n        assertEquals(\"S1\", myBean.getStringValue());\n        assertTrue(myBean.getMapValue().containsKey(\"A\"));\n    }\n\n    @Test\n    void testSetBeanPropsUnknownProperty() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"bogusValue\", Integer.valueOf(1));\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) { // ignore \n        }\n    }\n\n    @Test\n    void testSetBeanPropsNullPrimative() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"intValue\", null);\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) {\n            // ignore\n        }\n    }\n\n    @Test\n    void testSetBeanPropsNullNonPrimative() throws SchedulerException {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"mapValue\", null);\n        TestBean testBean = new TestBean();\n        testBean.setMapValue(Collections.singletonMap(\"A\", \"B\"));\n        factory.setBeanProps(testBean, jobDataMap);\n        assertNull(testBean.getMapValue());\n    }\n    @Test\n    void testSetBeanPropsWrongPrimativeType() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"intValue\", new Float(7));\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) {\n            // ignore\n        }\n    }\n\n    @Test\n    void testSetBeanPropsWrongNonPrimativeType() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"mapValue\", new Float(7));\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) {\n            // ignore\n        }\n    }\n\n    @Test\n    void testSetBeanPropsCharStringTooShort() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"charValue\", \"\");\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) {\n            // ignore\n        }\n    }\n\n    @Test\n    void testSetBeanPropsCharStringTooLong() {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"charValue\", \"abba\");\n        try {\n            factory.setBeanProps(new TestBean(), jobDataMap);\n            fail();\n        } catch (SchedulerException ignore) {\n            // ignore\n        }\n    }\n\n    @Test\n    void testSetBeanPropsFromStrings() throws SchedulerException {\n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(\"intValue\", \"1\");\n        jobDataMap.put(\"longValue\", \"2\");\n        jobDataMap.put(\"floatValue\", \"3.0\");\n        jobDataMap.put(\"doubleValue\", \"4.0\");\n        jobDataMap.put(\"booleanValue\", \"true\");\n        jobDataMap.put(\"shortValue\", \"5\");\n        jobDataMap.put(\"charValue\", \"a\");\n        jobDataMap.put(\"byteValue\", \"6\");\n        \n        TestBean myBean = new TestBean();\n        factory.setBeanProps(myBean, jobDataMap);\n        \n        assertEquals(1, myBean.getIntValue());\n        assertEquals(2l, myBean.getLongValue());\n        assertEquals(3.0f, myBean.getFloatValue(), 0.0001);\n        assertEquals(4.0, myBean.getDoubleValue(), 0.0001);\n        assertTrue(myBean.getBooleanValue());\n        assertEquals(5, myBean.getShortValue());\n        assertEquals('a', myBean.getCharValue());\n        assertEquals((byte)6, myBean.getByteValue());\n    }\n\n    private static final class TestBean {\n        private int intValue;\n        private long longValue;\n        private float floatValue;\n        private double doubleValue;\n        private boolean booleanValue;\n        private byte byteValue;\n        private short shortValue;\n        private char charValue;\n        private String stringValue;\n        private Map<?, ?> mapValue;\n    \n        public boolean getBooleanValue() {\n            return booleanValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setBooleanValue(boolean booleanValue) {\n            this.booleanValue = booleanValue;\n        }\n    \n        public double getDoubleValue() {\n            return doubleValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setDoubleValue(double doubleValue) {\n            this.doubleValue = doubleValue;\n        }\n    \n        public float getFloatValue() {\n            return floatValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setFloatValue(float floatValue) {\n            this.floatValue = floatValue;\n        }\n   \n        public int getIntValue() {\n            return intValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setIntValue(int intValue) {\n            this.intValue = intValue;\n        }\n    \n        public long getLongValue() {\n            return longValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setLongValue(long longValue) {\n            this.longValue = longValue;\n        }\n\n        public Map<?, ?> getMapValue() {\n            return mapValue;\n        }\n    \n        public void setMapValue(Map<?, ?> mapValue) {\n            this.mapValue = mapValue;\n        }\n    \n        public String getStringValue() {\n            return stringValue;\n        }\n    \n        @SuppressWarnings(\"unused\")\n        public void setStringValue(String stringValue) {\n            this.stringValue = stringValue;\n        }\n\n        public byte getByteValue() {\n            return byteValue;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setByteValue(byte byteValue) {\n            this.byteValue = byteValue;\n        }\n\n        public char getCharValue() {\n            return charValue;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setCharValue(char charValue) {\n            this.charValue = charValue;\n        }\n\n        public short getShortValue() {\n            return shortValue;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setShortValue(short shortValue) {\n            this.shortValue = shortValue;\n        }\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/simpl/RAMJobStoreTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.simpl;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.quartz.AbstractJobStoreTest;\nimport org.quartz.spi.JobStore;\n\npublic class RAMJobStoreTest extends AbstractJobStoreTest {\n    private HashMap<String, JobStore> stores = new HashMap<>();\n\n    @Override\n    protected JobStore createJobStore(String name) {\n        RAMJobStore rs = new RAMJobStore();\n        stores.put(name, rs);\n        return rs;\n    }\n\n    @Override\n    protected void destroyJobStore(String name) {\n\n    }\n\n    protected Map<String, JobStore> stores() {\n        return stores;\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/simpl/SystemPropertyInstanceIdGeneratorTest.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n */\npackage org.quartz.simpl;\n\nimport java.sql.SQLException;\nimport java.util.Properties;\n\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Scheduler;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Unit test for SystemPropertyInstanceIdGenerator.\n */\nclass SystemPropertyInstanceIdGeneratorTest  {\n\n  @BeforeEach\n  protected void setUp() throws Exception {\n    System.setProperty(SystemPropertyInstanceIdGenerator.SYSTEM_PROPERTY,\n        \"foo\");\n    System.setProperty(\"blah.blah\",\n    \"goo\");\n  }\n\n  @Test\n  void testGetInstanceId() throws Exception {\n    SystemPropertyInstanceIdGenerator gen = new SystemPropertyInstanceIdGenerator();\n\n    String instId = gen.generateInstanceId();\n\n    assertEquals(\"foo\", instId);\n  }\n\n  @Test\n  void testGetInstanceIdWithPrepend() throws Exception {\n    SystemPropertyInstanceIdGenerator gen = new SystemPropertyInstanceIdGenerator();\n    gen.setPrepend(\"1\");\n\n    String instId = gen.generateInstanceId();\n\n    assertEquals(\"1foo\", instId);\n  }\n\n  @Test\n  void testGetInstanceIdWithPostpend() throws Exception {\n    SystemPropertyInstanceIdGenerator gen = new SystemPropertyInstanceIdGenerator();\n    gen.setPostpend(\"2\");\n\n    String instId = gen.generateInstanceId();\n\n    assertEquals(\"foo2\", instId);\n  }\n\n  @Test\n  void testGetInstanceIdWithPrependAndPostpend() throws Exception {\n    SystemPropertyInstanceIdGenerator gen = new SystemPropertyInstanceIdGenerator();\n    gen.setPrepend(\"1\");\n    gen.setPostpend(\"2\");\n\n    String instId = gen.generateInstanceId();\n\n    assertEquals(\"1foo2\", instId);\n  }\n\n  @Test\n  void testGetInstanceIdFromCustomSystemProperty() throws Exception {\n    SystemPropertyInstanceIdGenerator gen = new SystemPropertyInstanceIdGenerator();\n    gen.setSystemPropertyName(\"blah.blah\");\n\n    String instId = gen.generateInstanceId();\n\n    assertEquals(\"goo\", instId);\n  }\n\n  @Test\n  void testGeneratorThroughSchedulerInstantiation() throws Exception {\n    try {\n        JdbcQuartzTestUtilities.createDatabase(\"MeSchedulerDatabase\", DatabaseType.DERBY);\n    } catch (SQLException e) {\n      throw new AssertionError(e);\n    }\n\n    Properties config = new Properties();\n    config.setProperty(\"org.quartz.scheduler.instanceName\", \"MeScheduler\");\n    config.setProperty(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n    config.setProperty(\"org.quartz.scheduler.instanceIdGenerator.class\", \n        org.quartz.simpl.SystemPropertyInstanceIdGenerator.class.getName());\n    config.setProperty(\"org.quartz.scheduler.instanceIdGenerator.prepend\", \"1\");\n    config.setProperty(\"org.quartz.scheduler.instanceIdGenerator.postpend\", \"2\");\n    config.setProperty(\"org.quartz.scheduler.instanceIdGenerator.systemPropertyName\", \"blah.blah\");\n    config.setProperty(\"org.quartz.threadPool.threadCount\", \"1\");\n    config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n    config.setProperty(\"org.quartz.jobStore.class\", org.quartz.impl.jdbcjobstore.JobStoreTX.class.getName());\n    config.setProperty(\"org.quartz.jobStore.isClustered\", \"true\");\n    config.setProperty(\"org.quartz.jobStore.dataSource\", \"MeSchedulerDatabase\");\n    \n    Scheduler sched = new StdSchedulerFactory(config).getScheduler();    \n    \n    assertEquals(\"1goo2\", sched.getSchedulerInstanceId());\n  }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/C3p0PoolingConnectionProviderTest.java",
    "content": "/*\r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\r\n * use this file except in compliance with the License. You may obtain a copy\r\n * of the License at\r\n *\r\n *   http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r\n * License for the specific language governing permissions and limitations\r\n * under the License.\r\n *\r\n */\r\n\r\npackage org.quartz.utils;\r\n\r\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\r\nimport org.hamcrest.Matchers;\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.quartz.integrations.tests.JdbcQuartzDerbyUtilities;\r\nimport org.quartz.integrations.tests.QuartzDerbyTestSupport;\r\n\r\nimport java.util.Properties;\r\n\r\nimport static org.hamcrest.MatcherAssert.assertThat;\r\n\r\n/**\r\n * A integration test to ensure PoolConnectionProvider is working properly.\r\n */\r\npublic class C3p0PoolingConnectionProviderTest extends QuartzDerbyTestSupport {\r\n    boolean testConnectionProviderClass = false;\r\n\r\n    @Test\r\n    void testC3p0PoolProviderWithExtraProps() throws Exception {\r\n        validateC3p0PoolProviderClassWithExtraProps();\r\n\r\n        // Turn flag on for next test.\r\n        testConnectionProviderClass = true;\r\n    }\r\n\r\n    @Test\r\n    void testC3p0PoolProviderClassWithExtraProps() throws Exception {\r\n        validateC3p0PoolProviderClassWithExtraProps();\r\n\r\n        // Turn flag off for next test.\r\n        testConnectionProviderClass = false;\r\n    }\r\n\r\n    private void validateC3p0PoolProviderClassWithExtraProps() {\r\n        DBConnectionManager dbManager = DBConnectionManager.getInstance();\r\n        ConnectionProvider provider = dbManager.getConnectionProvider(\"myDS\");\r\n\r\n        ComboPooledDataSource ds = ((C3p0PoolingConnectionProvider)provider).getDataSource();\r\n\r\n        assertThat(ds.getDriverClass(), Matchers.is(\"org.apache.derby.jdbc.ClientDriver\"));\r\n        assertThat(ds.getJdbcUrl(), Matchers.is(JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX));\r\n        assertThat(ds.getUser(), Matchers.is(\"quartz\"));\r\n        assertThat(ds.getPassword(), Matchers.is(\"quartz\"));\r\n        assertThat(ds.getMaxPoolSize(), Matchers.is(5));\r\n\r\n        assertThat(ds.getMinPoolSize(), Matchers.is(5));\r\n        assertThat(ds.getAcquireIncrement(), Matchers.is(5));\r\n        assertThat(ds.getAcquireRetryAttempts(), Matchers.is(3));\r\n        assertThat(ds.getAcquireRetryDelay(), Matchers.is(3000));\r\n    }\r\n\r\n\r\n\r\n    @Override\r\n    protected Properties createSchedulerProperties() {\r\n        Properties properties = new Properties();\r\n        properties.put(\"org.quartz.scheduler.instanceName\",\"TestScheduler\");\r\n        properties.put(\"org.quartz.scheduler.instanceId\",\"AUTO\");\r\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\",\"true\");\r\n        properties.put(\"org.quartz.threadPool.class\",\"org.quartz.simpl.SimpleThreadPool\");\r\n        properties.put(\"org.quartz.threadPool.threadCount\",\"12\");\r\n        properties.put(\"org.quartz.threadPool.threadPriority\",\"5\");\r\n        properties.put(\"org.quartz.jobStore.misfireThreshold\",\"10000\");\r\n        properties.put(\"org.quartz.jobStore.class\",\"org.quartz.impl.jdbcjobstore.JobStoreTX\");\r\n        properties.put(\"org.quartz.jobStore.driverDelegateClass\",\"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\r\n        properties.put(\"org.quartz.jobStore.useProperties\",\"true\");\r\n        properties.put(\"org.quartz.jobStore.dataSource\",\"myDS\");\r\n        properties.put(\"org.quartz.jobStore.tablePrefix\",\"QRTZ_\");\r\n        properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\r\n\r\n        if (testConnectionProviderClass)\r\n            properties.put(\"org.quartz.dataSource.myDS.connectionProvider.class\", \"org.quartz.utils.PoolingConnectionProvider\");\r\n\r\n        properties.put(\"org.quartz.dataSource.myDS.provider\", \"c3p0\");\r\n\r\n        properties.put(\"org.quartz.dataSource.myDS.driver\", \"org.apache.derby.jdbc.ClientDriver\");\r\n        properties.put(\"org.quartz.dataSource.myDS.URL\",JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX);\r\n        properties.put(\"org.quartz.dataSource.myDS.user\",\"quartz\");\r\n        properties.put(\"org.quartz.dataSource.myDS.password\",\"quartz\");\r\n        properties.put(\"org.quartz.dataSource.myDS.maxConnections\",\"5\");\r\n\r\n        // Set extra properties\r\n        properties.put(\"org.quartz.dataSource.myDS.minPoolSize\",\"5\");\r\n        properties.put(\"org.quartz.dataSource.myDS.acquireIncrement\",\"5\");\r\n        properties.put(\"org.quartz.dataSource.myDS.acquireRetryAttempts\",\"3\");\r\n        properties.put(\"org.quartz.dataSource.myDS.acquireRetryDelay\",\"3000\");\r\n        properties.put(\"org.quartz.dataSource.myDS.maxIdleTime\",\"60\");\r\n\r\n        return properties;\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/CircularLossyQueueTest.java",
    "content": "package org.quartz.utils;\n\nimport static org.junit.jupiter.api.Assertions.assertAll;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport org.junit.jupiter.api.Test;\n\nclass CircularLossyQueueTest {\n\n\t@Test\n\tvoid testNewCircularLossyQueueShouldBeEmpty() {\n\t\tLong[] array = new Long[5];\n\t\tCircularLossyQueue<Long> queue = new CircularLossyQueue<>(5);\n\t\tqueue.toArray(array);\n\n\t\tassertAll(\"emptyQueue\",\n\t\t\t\t() -> assertTrue(queue.isEmpty()),\n\t\t\t\t() -> assertNull(queue.peek()),\n\t\t\t\t() -> assertArrayEquals(new Long[] { null, null, null, null, null }, array)\n\t\t);\n\t}\n\n\t@Test\n\tvoid testPushIntoNotFullQueue() {\n\t\tLong[] array = new Long[5];\n\t\tCircularLossyQueue<Long> queue = new CircularLossyQueue<>(5);\n\n\t\tint depthBefore = queue.depth();\n\n\t\tqueue.push(1L);\n\t\tqueue.toArray(array);\n\n\t\tassertAll(\"pushIntoNotFullQueue\",\n\t\t\t\t() -> assertFalse(queue.isEmpty()),\n\t\t\t\t() -> assertEquals(depthBefore + 1, queue.depth()),\n\t\t\t\t() -> assertEquals(1L, queue.peek()),\n\t\t\t\t() -> assertArrayEquals(new Long[] { 1L, null, null, null, null }, array)\n\t\t);\n\t}\n\n\t@Test\n\tvoid testPushIntoFullQueue() {\n\t\tLong[] array = new Long[5];\n\t\tCircularLossyQueue<Long> queue = new CircularLossyQueue<>(5);\n\n\t\tfor (long value = 1L; value < 6L; value++) {\n\t\t\tqueue.push(value);\n\t\t}\n\n\t\tint depthBefore = queue.depth();\n\n\t\tqueue.push(6L);\n\t\tqueue.toArray(array);\n\n\t\tassertAll(\"pushIntoFullQueue\",\n\t\t\t\t() -> assertFalse(queue.isEmpty()),\n\t\t\t\t() -> assertEquals(depthBefore, queue.depth()),\n\t\t\t\t() -> assertEquals(6L, queue.peek()),\n\t\t\t\t() -> assertArrayEquals(new Long[] { 6L, 5L, 4L, 3L, 2L }, array)\n\t\t);\n\t}\n\n\t@Test\n\tvoid testToArrayShouldThrowWhenProvidedArrayIsBiggerThanInternalOne() {\n\t\tCircularLossyQueue<Long> queue = new CircularLossyQueue<>(5);\n\t\tLong[] array = new Long[10];\n\n\t\tassertThrows(IllegalArgumentException.class, () -> queue.toArray(array));\n\t}\n\n\t@Test\n\tvoid testToArray() {\n\t\tCircularLossyQueue<Long> queue = new CircularLossyQueue<>(5);\n\t\tLong[] array = new Long[5];\n\n\t\tfor (long value = 1L; value < 4L; value++) {\n\t\t\tqueue.push(value);\n\t\t}\n\n\t\tarray = queue.toArray(array);\n\t\tassertArrayEquals(new Long[] { 3L, 2L, 1L, null, null }, array);\n\n\t\tfor (long value = 4L; value < 9L; value++) {\n\t\t\tqueue.push(value);\n\t\t}\n\n\t\tarray = queue.toArray(array);\n\t\tassertArrayEquals(new Long[] { 8L, 7L, 6L, 5L, 4L }, array);\n\n\t}\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/ClassUtilsTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.utils;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.PersistJobDataAfterExecution;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n\n/**\n * @author Alex Snaps\n */\npublic class ClassUtilsTest  {\n\n    @Test\n    void testIsAnnotationPresentOnSuperClass() throws Exception {\n        assertTrue(ClassUtils.isAnnotationPresent(BaseJob.class, DisallowConcurrentExecution.class));\n        assertFalse(ClassUtils.isAnnotationPresent(BaseJob.class, PersistJobDataAfterExecution.class));\n        assertTrue(ClassUtils.isAnnotationPresent(ExtendedJob.class, DisallowConcurrentExecution.class));\n        assertFalse(ClassUtils.isAnnotationPresent(ExtendedJob.class, PersistJobDataAfterExecution.class));\n        assertTrue(ClassUtils.isAnnotationPresent(ReallyExtendedJob.class, DisallowConcurrentExecution.class));\n        assertTrue(ClassUtils.isAnnotationPresent(ReallyExtendedJob.class, PersistJobDataAfterExecution.class));\n    }\n\n    @DisallowConcurrentExecution\n    private static class BaseJob implements Job {\n        public void execute(final JobExecutionContext context) throws JobExecutionException {\n            System.out.println(this.getClass().getSimpleName());\n        }\n    }\n\n    private static class ExtendedJob extends BaseJob {\n    }\n\n    @PersistJobDataAfterExecution\n    private static class ReallyExtendedJob extends ExtendedJob {\n\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/DirtyFlagMapTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\n\n/**\n * Unit test for DirtyFlagMap.  These tests focus on making\n * sure the isDirty flag is set correctly.\n */\nclass DirtyFlagMapTest  {\n\n    @Test\n    void testClear() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        assertFalse(dirtyFlagMap.isDirty());\n\n        dirtyFlagMap.clear();\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"X\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        dirtyFlagMap.clear();\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @Test\n    void testPut() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        dirtyFlagMap.put(\"a\", \"Y\");\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @Test\n    void testRemove() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n\n        dirtyFlagMap.remove(\"b\");\n        assertFalse(dirtyFlagMap.isDirty());\n\n        dirtyFlagMap.remove(\"a\");\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @Test\n    void testEntrySetRemove() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        dirtyFlagMap.remove(\"a\");\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        entrySet.remove(\"b\");\n        assertFalse(dirtyFlagMap.isDirty());\n        entrySet.remove(entrySet.iterator().next());\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n    @Test\n    void testEntrySetRetainAll() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        entrySet.retainAll(Collections.EMPTY_LIST);\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        entrySet.retainAll(Collections.singletonList(entrySet.iterator().next()));\n        assertFalse(dirtyFlagMap.isDirty());\n        entrySet.retainAll(Collections.EMPTY_LIST);\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @Test\n    void testEntrySetRemoveAll() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        entrySet.removeAll(Collections.EMPTY_LIST);\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        entrySet.removeAll(Collections.EMPTY_LIST);\n        assertFalse(dirtyFlagMap.isDirty());\n        entrySet.removeAll(Collections.singletonList(entrySet.iterator().next()));\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @Test\n    void testEntrySetClear() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        entrySet.clear();\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        entrySet.clear();\n        assertTrue(dirtyFlagMap.isDirty());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testEntrySetIterator() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        dirtyFlagMap.put(\"a\", \"A\");\n        dirtyFlagMap.put(\"b\", \"B\");\n        dirtyFlagMap.put(\"c\", \"C\");\n        dirtyFlagMap.clearDirtyFlag();\n        Iterator<?> entrySetIter = entrySet.iterator();\n        Map.Entry<?, ?> entryToBeRemoved = (Map.Entry<?, ?>) entrySetIter.next();\n        String removedKey = (String) entryToBeRemoved.getKey();\n        entrySetIter.remove();\n        assertEquals(2, dirtyFlagMap.size());\n        assertTrue(dirtyFlagMap.isDirty());\n        assertFalse(dirtyFlagMap.containsKey(removedKey));\n        dirtyFlagMap.clearDirtyFlag();\n        Map.Entry<?, String> entry = (Map.Entry<?, String>) entrySetIter.next();\n        entry.setValue(\"BB\");\n        assertTrue(dirtyFlagMap.isDirty());\n        assertTrue(dirtyFlagMap.containsValue(\"BB\"));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testEntrySetToArray() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        dirtyFlagMap.put(\"a\", \"A\");\n        dirtyFlagMap.put(\"b\", \"B\");\n        dirtyFlagMap.put(\"c\", \"C\");\n        dirtyFlagMap.clearDirtyFlag();\n        Object[] array = entrySet.toArray();\n        assertEquals(3, array.length);\n        Map.Entry<?, String> entry = (Map.Entry<?, String>) array[0];\n        entry.setValue(\"BB\");\n        assertTrue(dirtyFlagMap.isDirty());\n        assertTrue(dirtyFlagMap.containsValue(\"BB\"));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testEntrySetToArrayWithArg() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<Map.Entry<String, String>> entrySet = dirtyFlagMap.entrySet();\n        dirtyFlagMap.put(\"a\", \"A\");\n        dirtyFlagMap.put(\"b\", \"B\");\n        dirtyFlagMap.put(\"c\", \"C\");\n        dirtyFlagMap.clearDirtyFlag();\n        Object[] array = entrySet.toArray(new Map.Entry[]{});\n        assertEquals(3, array.length);\n        Map.Entry<?, String> entry = (Map.Entry<?, String>) array[0];\n        entry.setValue(\"BB\");\n        assertTrue(dirtyFlagMap.isDirty());\n        assertTrue(dirtyFlagMap.containsValue(\"BB\"));\n    }\n    @Test\n    void testKeySetClear() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Set<?> keySet = dirtyFlagMap.keySet();\n        keySet.clear();\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        keySet.clear();\n        assertTrue(dirtyFlagMap.isDirty());\n        assertEquals(0, dirtyFlagMap.size());\n    }\n\n    @Test\n    void testValuesClear() {\n        DirtyFlagMap<String, String> dirtyFlagMap = new DirtyFlagMap<String, String>();\n        Collection<?> values = dirtyFlagMap.values();\n        values.clear();\n        assertFalse(dirtyFlagMap.isDirty());\n        dirtyFlagMap.put(\"a\", \"Y\");\n        dirtyFlagMap.clearDirtyFlag();\n        values.clear();\n        assertTrue(dirtyFlagMap.isDirty());\n        assertEquals(0, dirtyFlagMap.size());\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/HikariCpPoolingConnectionProviderTest.java",
    "content": "\n/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n *\n */\n\npackage org.quartz.utils;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.hamcrest.Matchers;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.integrations.tests.JdbcQuartzDerbyUtilities;\nimport org.quartz.integrations.tests.QuartzDerbyTestSupport;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n/**\n * A integration test to ensure PoolConnectionProvider is working properly.\n */\npublic class HikariCpPoolingConnectionProviderTest extends QuartzDerbyTestSupport {\n    boolean testConnectionProviderClass = false;\n\n    @Test\n    void testHikariCpPoolProviderWithExtraProps() throws Exception {\n        validateHikariCpPoolProviderClassWithExtraProps();\n\n        // Turn flag on for next test.\n        testConnectionProviderClass = true;\n    }\n\n    @Test\n    void testHikariCpPoolProviderClassWithExtraProps() throws Exception {\n        validateHikariCpPoolProviderClassWithExtraProps();\n\n        // Turn flag off for next test.\n        testConnectionProviderClass = false;\n    }\n\n    private void validateHikariCpPoolProviderClassWithExtraProps() {\n        DBConnectionManager dbManager = DBConnectionManager.getInstance();\n        ConnectionProvider provider = dbManager.getConnectionProvider(\"myDS\");\n\n        HikariDataSource ds = ((HikariCpPoolingConnectionProvider)provider).getDataSource();\n\n        assertThat(ds.getDriverClassName(), Matchers.is(\"org.apache.derby.jdbc.ClientDriver\"));\n        assertThat(ds.getJdbcUrl(), Matchers.is(JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX));\n        assertThat(ds.getUsername(), Matchers.is(\"quartz\"));\n        assertThat(ds.getPassword(), Matchers.is(\"quartz\"));\n        assertThat(ds.getMaximumPoolSize(), Matchers.is(5));\n\n        assertThat(ds.getTransactionIsolation(), Matchers.is(\"TRANSACTION_REPEATABLE_READ\"));\n        assertThat(ds.isReadOnly(), Matchers.is(false));\n        assertThat(ds.isAutoCommit(), Matchers.is(false));\n    }\n\n\n\n    @Override\n    protected Properties createSchedulerProperties() {\n        Properties properties = new Properties();\n        properties.put(\"org.quartz.scheduler.instanceName\",\"TestScheduler\");\n        properties.put(\"org.quartz.scheduler.instanceId\",\"AUTO\");\n        properties.put(\"org.quartz.scheduler.skipUpdateCheck\",\"true\");\n        properties.put(\"org.quartz.threadPool.class\",\"org.quartz.simpl.SimpleThreadPool\");\n        properties.put(\"org.quartz.threadPool.threadCount\",\"12\");\n        properties.put(\"org.quartz.threadPool.threadPriority\",\"5\");\n        properties.put(\"org.quartz.jobStore.misfireThreshold\",\"10000\");\n        properties.put(\"org.quartz.jobStore.class\",\"org.quartz.impl.jdbcjobstore.JobStoreTX\");\n        properties.put(\"org.quartz.jobStore.driverDelegateClass\",\"org.quartz.impl.jdbcjobstore.StdJDBCDelegate\");\n        properties.put(\"org.quartz.jobStore.useProperties\",\"true\");\n        properties.put(\"org.quartz.jobStore.dataSource\",\"myDS\");\n        properties.put(\"org.quartz.jobStore.tablePrefix\",\"QRTZ_\");\n        properties.put(\"org.quartz.jobStore.isClustered\", \"false\");\n\n        properties.put(\"org.quartz.dataSource.myDS.provider\", \"hikaricp\");\n\n        if (testConnectionProviderClass)\n            properties.put(\"org.quartz.dataSource.myDS.connectionProvider.class\", \"org.quartz.utils.HikariCpPoolingConnectionProvider\");\n\n        properties.put(\"org.quartz.dataSource.myDS.provider\", \"hikaricp\");\n        properties.put(\"org.quartz.dataSource.myDS.driver\", \"org.apache.derby.jdbc.ClientDriver\");\n        properties.put(\"org.quartz.dataSource.myDS.URL\",JdbcQuartzDerbyUtilities.DATABASE_CONNECTION_PREFIX);\n        properties.put(\"org.quartz.dataSource.myDS.username\",\"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.password\",\"quartz\");\n        properties.put(\"org.quartz.dataSource.myDS.maxConnections\",\"5\");\n\n        // Set extra properties\n        properties.put(\"org.quartz.dataSource.myDS.transactionIsolation\",\"TRANSACTION_REPEATABLE_READ\");\n        properties.put(\"org.quartz.dataSource.myDS.readOnly\",\"false\");\n        properties.put(\"org.quartz.dataSource.myDS.autoCommit\",\"false\");\n\n        return properties;\n    }\n}"
  },
  {
    "path": "quartz/src/test/java/org/quartz/utils/PropertiesParserTest.java",
    "content": "/*\r\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\r\n * Copyright IBM Corp. 2024, 2025\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage org.quartz.utils;\r\n\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport java.util.Properties;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\n\r\n\r\n/**\r\n * Unit tests for PropertiesParser.\r\n */\r\npublic class PropertiesParserTest  {\r\n\r\n    /**\r\n     * Unit test for full getPropertyGroup() method.\r\n     */\r\n    @Test\r\n    void testGetPropertyGroupStringBooleanStringArray() {\r\n        // Test that an empty property does not cause an exception\r\n        Properties props = new Properties();\r\n        props.put(\"x.y.z\", \"\");\r\n        \r\n        PropertiesParser propertiesParser = new PropertiesParser(props);\r\n        Properties propGroup = propertiesParser.getPropertyGroup(\"x.y\", true, new String[] {});\r\n        assertEquals(\"\", propGroup.getProperty(\"z\"));\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/xml/XMLSchedulingDataProcessorPluginTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.xml;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.*;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.simpl.CascadingClassLoadHelper;\nimport org.quartz.spi.ClassLoadHelper;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class XMLSchedulingDataProcessorPluginTest  implements TriggerListener {\n\n    CountDownLatch latch = new CountDownLatch(1);\n    boolean jobRan = false;\n\n    @Test\n    void testPluginSchedulesFromSimpleXMLFile() throws Exception {\n        Scheduler scheduler = null;\n        try {\n            StdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-xml-plugin-test.properties\");\n            scheduler = factory.getScheduler();\n\n            scheduler.getListenerManager().addTriggerListener(this);\n            scheduler.start();\n            latch.await(1, TimeUnit.MINUTES);\n\n            assert(jobRan);\n        } finally {\n            if (scheduler != null)\n                scheduler.shutdown();\n        }\n    }\n\n    @Override\n    public String getName() {\n        return \"XMLSchedulingDataProcessorPluginTestListener\";\n    }\n\n    @Override\n    public void triggerFired(Trigger trigger, JobExecutionContext context) {\n        jobRan = true;\n        latch.countDown();\n    }\n\n    @Override\n    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {\n        return false;\n    }\n\n    @Override\n    public void triggerMisfired(Trigger trigger) {\n\n    }\n\n    @Override\n    public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) {\n\n    }\n\n}\n"
  },
  {
    "path": "quartz/src/test/java/org/quartz/xml/XMLSchedulingDataProcessorTest.java",
    "content": "package org.quartz.xml;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.SimpleScheduleBuilder.repeatHourlyForever;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\nimport java.util.TimeZone;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.JobKey;\nimport org.quartz.ObjectAlreadyExistsException;\nimport org.quartz.Scheduler;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.DirectSchedulerFactory;\nimport org.quartz.impl.SchedulerRepository;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities;\nimport org.quartz.impl.jdbcjobstore.JdbcQuartzTestUtilities.DatabaseType;\nimport org.quartz.impl.jdbcjobstore.JobStoreTX;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.simpl.CascadingClassLoadHelper;\nimport org.quartz.simpl.SimpleThreadPool;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.utils.DBConnectionManager;\nimport org.xml.sax.SAXParseException;\n\n/**\n * Unit test for XMLSchedulingDataProcessor.\n *\n * @author Zemian Deng\n * @author Tomasz Nurkiewicz (QTZ-273)\n */\npublic class XMLSchedulingDataProcessorTest  {\n\n\t/** QTZ-185\n\t * <p>The default XMLSchedulingDataProcessor will setOverWriteExistingData(true), and we want to\n\t * test programmatically overriding this value.\n\t * \n\t * <p>Note that XMLSchedulingDataProcessor#processFileAndScheduleJobs(Scheduler,boolean) will only\n\t * read default \"quartz_data.xml\" in current working directory. So to test this, we must create\n\t * this file. If this file already exist, it will be overwritten! \n\t */\n\tvoid testOverwriteFlag() throws Exception {\n\t\t//Prepare a quartz_data.xml in current working directory by copy a test case file.\n\t\tFile file = new File(XMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME);\n\t\tcopyResourceToFile(\"/org/quartz/xml/simple-job-trigger.xml\", file);\n\t\t\n\t\tScheduler scheduler = null;\n\t\ttry {\n\t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n\t\t\tscheduler = factory.getScheduler();\n\t\t\t\n\t\t\t// Let's setup a fixture job data that we know test is not going modify it.\n\t\t\tJobDetail job = newJob(MyJob.class).withIdentity(\"job1\").usingJobData(\"foo\", \"dont_chg_me\").build();\n\t\t\tTrigger trigger = newTrigger().withIdentity(\"job1\").withSchedule(repeatHourlyForever()).build();\n\t\t\tscheduler.scheduleJob(job, trigger);\t\t\t\n\t\t\t\n\t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n\t\t\tclhelper.initialize();\n\t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\t\t\ttry {\n\t\t\t\tprocessor.processFileAndScheduleJobs(scheduler, false);\n\t\t\t\tfail(\"OverWriteExisting flag didn't work. We should get Exception when overwrite is set to false.\");\n\t\t\t} catch (ObjectAlreadyExistsException e) {\n\t\t\t\t// This is expected. Do nothing.\n\t\t\t}\n\t\t\t\n\t\t\t// We should still have what we start with.\n\t\t\tassertEquals(1, scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"DEFAULT\")).size());\n\t\t\tassertEquals(1, scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"DEFAULT\")).size());\n\t\t\t\n\t\t\tjob = scheduler.getJobDetail(JobKey.jobKey(\"job1\"));\n\t\t\tString fooValue = job.getJobDataMap().getString(\"foo\");\n\t\t\tassertEquals(\"dont_chg_me\", fooValue);\n\t\t} finally {\n\t\t\t// remove test file\n\t\t\tif(file.exists() && !file.delete())\n\t\t\t\tthrow new RuntimeException(\"Failed to remove test file \" + file);\n\t\t\t\n\t\t\t// shutdown scheduler\n\t\t\tif (scheduler != null)\n\t\t\t\tscheduler.shutdown();\n\t\t}\n\t}\n\t\n\tprivate void copyResourceToFile(String resName, File file) throws IOException {\n\t\t// Copy streams\n\t\tInputStream inStream = null;\n\t\tFileOutputStream outStream = null;\n\t\ttry {\n\t\t\t// Copy input resource stream to output file.\n\t\t\tinStream = getClass().getResourceAsStream(resName);\n\t\t\toutStream = new FileOutputStream(file);\n\t\t\t\n\t\t\tint BLOCK_SIZE = 1024 * 1024 * 5; // 5 MB\n\t\t\tbyte[] buffer = new byte[BLOCK_SIZE];\n\t\t\tint len = -1;\n\t\t\twhile ((len = inStream.read(buffer, 0, BLOCK_SIZE)) != -1) {\n\t\t\t\toutStream.write(buffer, 0, len);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (outStream != null)\n\t\t\t\toutStream.close();\n\t\t\tif (inStream != null)\n\t\t\t\tinStream.close();\n\t\t}\n\t}\n\t\n\t/** QTZ-187 */\n\t@Test\n\tvoid testDirectivesNoOverwriteWithIgnoreDups() throws Exception {\n\t\tScheduler scheduler = null;\n\t\ttry {\n\t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n\t\t\tscheduler = factory.getScheduler();\n\t\t\t\n\t\t\t// Setup existing job with same names as in xml data.\n\t\t\tJobDetail job = newJob(MyJob.class).withIdentity(\"job1\").build();\n\t\t\tTrigger trigger = newTrigger().withIdentity(\"job1\").withSchedule(repeatHourlyForever()).build();\n\t\t\tscheduler.scheduleJob(job, trigger);\n\t\t\t\n\t\t\tjob = newJob(MyJob.class).withIdentity(\"job2\").build();\n\t\t\ttrigger = newTrigger().withIdentity(\"job2\").withSchedule(repeatHourlyForever()).build();\n\t\t\tscheduler.scheduleJob(job, trigger);\n\t\t\t\n\t\t\t// Now load the xml data with directives: overwrite-existing-data=false, ignore-duplicates=true\n\t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n\t\t\tclhelper.initialize();\n\t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\t\t\tprocessor.processFileAndScheduleJobs(\"org/quartz/xml/directives_no-overwrite_ignoredups.xml\", scheduler);\n\t\t\tassertEquals(2, scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"DEFAULT\")).size());\n\t\t\tassertEquals(2, scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"DEFAULT\")).size());\n\t\t} finally {\n\t\t\tif (scheduler != null)\n\t\t\t\tscheduler.shutdown();\n\t\t}\n\t}\n\t@Test\n    void testDirectivesOverwriteWithNoIgnoreDups() throws Exception {\n        Scheduler scheduler = null;\n        try {\n            StdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n            scheduler = factory.getScheduler();\n\n            // Setup existing job with same names as in xml data.\n            JobDetail job = newJob(MyJob.class).withIdentity(\"job1\").build();\n            Trigger trigger = newTrigger().withIdentity(\"job1\").withSchedule(repeatHourlyForever()).build();\n            scheduler.scheduleJob(job, trigger);\n\n            job = newJob(MyJob.class).withIdentity(\"job2\").build();\n            trigger = newTrigger().withIdentity(\"job2\").withSchedule(repeatHourlyForever()).build();\n            scheduler.scheduleJob(job, trigger);\n\n            // Now load the xml data with directives: overwrite-existing-data=false, ignore-duplicates=true\n            ClassLoadHelper clhelper = new CascadingClassLoadHelper();\n            clhelper.initialize();\n            XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n            processor.processFileAndScheduleJobs(\"org/quartz/xml/directives_overwrite_no-ignoredups.xml\", scheduler);\n            assertEquals(2, scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"DEFAULT\")).size());\n            assertEquals(2, scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"DEFAULT\")).size());\n        } finally {\n            if (scheduler != null)\n                scheduler.shutdown();\n        }\n    }\n\t\n\t/** QTZ-180 */\n\t@Test\n\tvoid testXsdSchemaValidationOnVariousTriggers() throws Exception {\n\t\tScheduler scheduler = null;\n\t\ttry {\n\t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n\t\t\tscheduler = factory.getScheduler();\n\t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n\t\t\tclhelper.initialize();\n\t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\t\t\tprocessor.processFileAndScheduleJobs(\"org/quartz/xml/job-scheduling-data-2.0_trigger-samples.xml\", scheduler);\n\t\t\tassertEquals(1, scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"DEFAULT\")).size());\n\t\t\tassertEquals(35, scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"DEFAULT\")).size());\n\t\t} finally {\n\t\t\tif (scheduler != null)\n\t\t\t\tscheduler.shutdown();\n\t\t}\n\t}\n\t@Test\n   \tvoid testQTZ327SimpleTriggerNoRepeat() throws Exception {\n   \t\tScheduler scheduler = null;\n   \t\ttry {\n   \t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n   \t\t\tscheduler = factory.getScheduler();\n   \t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n   \t\t\tclhelper.initialize();\n   \t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n   \t\t\tprocessor.processFileAndScheduleJobs(\"org/quartz/xml/simple-job-trigger-no-repeat.xml\", scheduler);\n   \t\t\tassertEquals(1, scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"DEFAULT\")).size());\n   \t\t\tassertEquals(1, scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"DEFAULT\")).size());\n   \t\t} finally {\n   \t\t\tif (scheduler != null)\n   \t\t\t\tscheduler.shutdown();\n   \t\t}\n   \t}\n\n\tprivate Date dateOfGMT_UTC(int hour, int minute, int second, int dayOfMonth, int month, int year) {\n\t\tfinal GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(\"GMT\"));\n\t\tcalendar.set(year, month, dayOfMonth, hour, minute, second);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\treturn calendar.getTime();\n\n\t}\n\t\n\tprivate Date dateOfLocalTime(int hour, int minute, int second, int dayOfMonth, int month, int year) {\n\t\tfinal GregorianCalendar calendar = new GregorianCalendar();\n\t\tcalendar.set(year, month, dayOfMonth, hour, minute, second);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\treturn calendar.getTime();\n\t}\n\n\t/** QTZ-273 */\n\t@Test\n\tvoid testTimeZones() throws Exception {\n\t\tScheduler scheduler = null;\n\t\ttry {\n\t\t\t// given\n\t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n\t\t\tscheduler = factory.getScheduler();\n\t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n\t\t\tclhelper.initialize();\n\t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\n\t\t\t// when\n\t\t\tprocessor.processFileAndScheduleJobs(\"org/quartz/xml/simple-job-trigger-with-timezones.xml\", scheduler);\n\n\t\t\t// then\n\t\t\tTrigger trigger = scheduler.getTrigger(new TriggerKey(\"job1\", \"DEFAULT\"));\n\t\t\tassertNotNull(trigger);\n\n\t\t\tassertEquals(dateOfGMT_UTC(18, 0, 0, 1, Calendar.JANUARY, 2012), trigger.getStartTime());\n\t\t\tassertEquals(dateOfGMT_UTC(19, 0, 0, 1, Calendar.JANUARY, 2012), trigger.getEndTime());\n\t\t\t\n\t\t\t\n\t\t\ttrigger = scheduler.getTrigger(new TriggerKey(\"job2\", \"DEFAULT\"));\n\t\t\tassertNotNull(trigger);\n\n\t\t\tassertEquals(dateOfLocalTime(6, 0, 0, 1, Calendar.JANUARY, 2012), trigger.getStartTime());\n\t\t\tassertEquals(dateOfGMT_UTC(19, 0, 0, 1, Calendar.JANUARY, 2012), trigger.getEndTime());\n\t\t} finally {\n\t\t\tif (scheduler != null)\n\t\t\t\tscheduler.shutdown();\n\t\t}\n\t}\n\n\t/** An empty job for testing purpose. */\n\tpublic static class MyJob implements Job {\n\t\tpublic void execute(JobExecutionContext context) throws JobExecutionException {\n\t\t\t//\n\t\t}\n\t}\n\n    /** Test for QTZ-353, where it requires a JDBC storage */\n\tvoid testRemoveJobClassNotFound() throws Exception {\n        String DB_NAME = \"XmlDeleteNonExistsJobTestDatabase\";\n        String SCHEDULER_NAME = \"XmlDeleteNonExistsJobTestScheduler\";\n        JdbcQuartzTestUtilities.createDatabase(DB_NAME, DatabaseType.DERBY);\n\n        JobStoreTX jobStore = new JobStoreTX();\n        jobStore.setDataSource(DB_NAME);\n        jobStore.setTablePrefix(\"QRTZ_\");\n        jobStore.setInstanceId(\"AUTO\");\n        DirectSchedulerFactory.getInstance().createScheduler(SCHEDULER_NAME, \"AUTO\", new SimpleThreadPool(4, Thread.NORM_PRIORITY), jobStore);\n        Scheduler scheduler = SchedulerRepository.getInstance().lookup(SCHEDULER_NAME);\n        try {\n            JobDetail jobDetail = JobBuilder.newJob(MyJob.class)\n                    .withIdentity(\"testjob1\", \"DEFAULT\")\n                    .usingJobData(\"foo\", \"foo\")\n                    .build();\n            Trigger trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"testjob1\", \"DEFAULT\")\n                    .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\"))\n                    .build();\n            scheduler.scheduleJob(jobDetail, trigger);\n\n            JobDetail jobDetail2 = scheduler.getJobDetail(jobDetail.getKey());\n            Trigger trigger2 = scheduler.getTrigger(trigger.getKey());\n            assertThat(jobDetail2.getJobDataMap().getString(\"foo\"), Matchers.is(\"foo\"));\n            assertThat(trigger2, Matchers.instanceOf(CronTrigger.class));\n\n            modifyStoredJobClassName();\n\n            ClassLoadHelper clhelper = new CascadingClassLoadHelper();\n            clhelper.initialize();\n            XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\n            processor.processFileAndScheduleJobs(\"org/quartz/xml/delete-no-jobclass.xml\", scheduler);\n\n            jobDetail2 = scheduler.getJobDetail(jobDetail.getKey());\n            trigger2 = scheduler.getTrigger(trigger.getKey());\n            assertThat(trigger2, Matchers.nullValue());\n            assertThat(jobDetail2, Matchers.nullValue());\n\n            jobDetail2 = scheduler.getJobDetail(new JobKey(\"job1\", \"DEFAULT\"));\n            trigger2 = scheduler.getTrigger(new TriggerKey(\"job1\", \"DEFAULT\"));\n            assertThat(jobDetail2.getJobDataMap().getString(\"foo\"), Matchers.is(\"bar\"));\n            assertThat(trigger2, Matchers.instanceOf(SimpleTrigger.class));\n        } finally {\n            scheduler.shutdown(false);\n            JdbcQuartzTestUtilities.destroyDatabase(DB_NAME, DatabaseType.DERBY);\n        }\n    }\n\n\t@Test\n    void testOverwriteJobClassNotFound() throws Exception {\n        String DB_NAME = \"XmlDeleteNonExistsJobTestDatabase\";\n        String SCHEDULER_NAME = \"XmlDeleteNonExistsJobTestScheduler\";\n        JdbcQuartzTestUtilities.createDatabase(DB_NAME, DatabaseType.DERBY);\n\n        JobStoreTX jobStore = new JobStoreTX();\n        jobStore.setDataSource(DB_NAME);\n        jobStore.setTablePrefix(\"QRTZ_\");\n        jobStore.setInstanceId(\"AUTO\");\n        DirectSchedulerFactory.getInstance().createScheduler(SCHEDULER_NAME, \"AUTO\", new SimpleThreadPool(4, Thread.NORM_PRIORITY), jobStore);\n        Scheduler scheduler = SchedulerRepository.getInstance().lookup(SCHEDULER_NAME);\n        try {\n            JobDetail jobDetail = JobBuilder.newJob(MyJob.class)\n                    .withIdentity(\"job1\", \"DEFAULT\")\n                    .usingJobData(\"foo\", \"foo\")\n                    .build();\n            Trigger trigger = TriggerBuilder.newTrigger()\n                    .withIdentity(\"job1\", \"DEFAULT\")\n                    .withSchedule(CronScheduleBuilder.cronSchedule(\"* * * * * ?\"))\n                    .build();\n            scheduler.scheduleJob(jobDetail, trigger);\n\n            JobDetail jobDetail2 = scheduler.getJobDetail(jobDetail.getKey());\n            Trigger trigger2 = scheduler.getTrigger(trigger.getKey());\n            assertThat(jobDetail2.getJobDataMap().getString(\"foo\"), Matchers.is(\"foo\"));\n            assertThat(trigger2, Matchers.instanceOf(CronTrigger.class));\n\n            modifyStoredJobClassName();\n\n            ClassLoadHelper clhelper = new CascadingClassLoadHelper();\n            clhelper.initialize();\n            XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\n            processor.processFileAndScheduleJobs(\"org/quartz/xml/overwrite-no-jobclass.xml\", scheduler);\n\n            jobDetail2 = scheduler.getJobDetail(jobDetail.getKey());\n            trigger2 = scheduler.getTrigger(trigger.getKey());\n            assertThat(jobDetail2.getJobDataMap().getString(\"foo\"), Matchers.is(\"bar\"));\n            assertThat(trigger2, Matchers.instanceOf(SimpleTrigger.class));\n        } finally {\n            scheduler.shutdown(false);\n            JdbcQuartzTestUtilities.destroyDatabase(DB_NAME, DatabaseType.DERBY);\n        }\n    }\n\n\t@Test\n\tvoid testXmlParserConfiguration() throws Exception {\n\t\tScheduler scheduler = null;\n\t\ttry {\n\t\t\tStdSchedulerFactory factory = new StdSchedulerFactory(\"org/quartz/xml/quartz-test.properties\");\n\t\t\tscheduler = factory.getScheduler();\n\t\t\tClassLoadHelper clhelper = new CascadingClassLoadHelper();\n\t\t\tclhelper.initialize();\n\t\t\tXMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(clhelper);\n\t\t\tprocessor.processFileAndScheduleJobs(\"org/quartz/xml/bad-job-config.xml\", scheduler);\n\n\n\t\t\tfinal JobKey jobKey = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"native\")).iterator().next();\n\t\t\tfinal JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n\t\t\tfinal String description = jobDetail.getDescription();\n\n\n\t\t\tfail(\"Expected parser configuration to block DOCTYPE. The following was injected into the job description field: \" + description);\n\t\t} catch (SAXParseException e) {\n\t\t\tassertTrue(e.getMessage().toLowerCase().contains(\"doctype\"));\n\t\t} finally {\n\t\t\tif (scheduler != null)\n\t\t\t\tscheduler.shutdown();\n\t\t}\n\t}\n\n\t@Test\n    private void modifyStoredJobClassName() throws Exception {\n        String DB_NAME = \"XmlDeleteNonExistsJobTestDatabase\";\n        Connection conn = DBConnectionManager.getInstance().getConnection(DB_NAME);\n        Statement statement = conn.createStatement();\n        statement.executeUpdate(\"update qrtz_job_details set job_class_name='com.FakeNonExistsJob'\");\n        statement.close();\n        conn.close();\n    }\n}\n"
  },
  {
    "path": "quartz/src/test/resources/container-license-acceptance.txt",
    "content": "mcr.microsoft.com/mssql/server:latest"
  },
  {
    "path": "quartz/src/test/resources/log4j.properties",
    "content": "# Configure logging for testing\nlog4j.rootLogger=INFO, stdout\n#log4j.logger.org.quartz=DEBUG\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n\n"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/properties/quartzCustomConnectionProvider.properties",
    "content": "# Main Quartz configuration\norg.quartz.scheduler.instanceName = DatabaseScheduler\norg.quartz.scheduler.instanceId = NON_CLUSTERED\norg.quartz.scheduler.jobFactory.class = org.quartz.simpl.SimpleJobFactory\norg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\norg.quartz.jobStore.dataSource = quartzDataSource\norg.quartz.jobStore.tablePrefix = QRTZ_\norg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount = 5\n\n# JobStore: JDBC jobStoreTX\norg.quartz.dataSource.quartzDataSource.connectionProvider.class = org.quartz.impl.MockConnectionProvider\norg.quartz.dataSource.quartzDataSource.customProperty = customValue\n\n"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/bad-job-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE foo [<!ELEMENT foo ANY >\n\t\t<!ENTITY xxe SYSTEM \"/\" >]>\n<job-scheduling-data xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\" version=\"2.0\">\n\t<schedule>\n\t\t<job>\n\t\t\t<name>xxe</name>\n\t\t\t<group>native</group>\n\t\t\t<description>&xxe;</description>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<durability>true</durability>\n\t\t\t<recover>false</recover>\n\t\t</job>\n\t</schedule>\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/delete-no-jobclass.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\n    <pre-processing-commands>\n        <delete-job>\n            <name>testjob1</name>\n            <group>DEFAULT</group>\n        </delete-job>\n    </pre-processing-commands>\n\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<job-data-map>\n\t\t\t\t<entry><key>foo</key><value>bar</value></entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/directives_no-overwrite_ignoredups.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!-- \nTest case for directives.\n\nTest should prepare a scheduler that already contains this job and trigger names.\n -->\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\t\n\t<processing-directives>\n\t\t<overwrite-existing-data>false</overwrite-existing-data>\n\t\t<ignore-duplicates>true</ignore-duplicates>\n\t</processing-directives>\n\t\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t\t<job>\n\t\t\t<name>job2</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<job-data-map>\n\t\t\t\t<entry>\n\t\t\t\t\t<key>color</key>\n\t\t\t\t\t<value>GREEN</value>\n\t\t\t\t</entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>job2</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job2</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<cron-expression>* * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/directives_overwrite_no-ignoredups.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!-- \nTest case for directives.\n\nTest should prepare a scheduler that already contains this job and trigger names.\n -->\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\t\n\t<processing-directives>\n\t\t<overwrite-existing-data>true</overwrite-existing-data>\n\t\t<ignore-duplicates>false</ignore-duplicates>\n\t</processing-directives>\n\t\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t\t<job>\n\t\t\t<name>job2</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<job-data-map>\n\t\t\t\t<entry>\n\t\t\t\t\t<key>color</key>\n\t\t\t\t\t<value>GREEN</value>\n\t\t\t\t</entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>job2</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job2</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<cron-expression>* * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/job-scheduling-data-2.0_trigger-samples.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<job-scheduling-data \n\txmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData job_scheduling_data_2_0.xsd\">\n\t\n\t<schedule>\n\t\n\t\t<!-- Sample job1 for all trigger testing. -->\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<durability>true</durability>\n\t\t\t<recover>false</recover>\n\t\t</job>\n\t\t\n\t\t<!-- Typical/Normal 6 fields cron -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_sec_no_day_of_week</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>* * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_sec_no_day_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>* * * ? * *</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_min</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_hour</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_day</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_first_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 1 * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_first_of_JAN</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 1 1 ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- Ranges -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_day_8am_to_5pm</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 8-17 * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_weekdays_8am_to_5pm</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 8-17 ? * MON-FRI</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_weekdays_8am_to_5pm_JUN_ot_SEP</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 8-17 ? JUN-SEP MON-FRI</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_weekdays_8am_to_5pm_JUN_ot_SEP_within_years</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 8-17 ? JUN-SEP MON-FRI 1970-2099</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- The L character -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>last_day_of_work_OR_SAT</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 ? * L</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>last_FRI_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 ? * 6L</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>last_SAT_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 ? * SATL</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>last_day_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 L * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!--  The new offset of month feature added in Quartz 2.0 -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>third_to_last_day_of_month</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 L-3 * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\t\t\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>31th_to_last_day_of_month_or_new_offset_feature_in_2_0</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 15 10 L-30 * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- The W character: you can not use it by itself! -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_weekdays_near_first_of_month_at_noon_time</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 12 1W * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_weekdays_near_last_day_of_month_at_noon_time</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 12 LW * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- The optional Year field -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>unspecified_year</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>specific_year</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 * * * * ? 2099</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>year_range</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 * * * * ? 2012-2099</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>any_year</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 * * * * ? *</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- \"the nth\" XXX day of the month for day-of-week field only -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_4th_MON_of_month_at_12AM</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 ? * 2#4</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_4th_TUE_of_month_at_12AM</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 ? * TUE#4</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\t\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_4th_TUE_of_month_at_12AM_in_2050</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 ? * WED#4 2050</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!-- Specific values -->\t\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_MON_WED_FRI_of_month_at_12AM</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 ? * MON,WED,FRI</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_1st_and_15th_of_month_at_12AM</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 1,15 * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>1st_and_15th_of_JAN_JUN_DEC_at_12AM</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 1,15 JAN,JUN,DEC ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>1st_and_15th_of_JAN_JUN_DEC_at_12AM_year_50_n_51</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0 0 0 1,15 JAN,JUN,DEC ? 2050,2051</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t\n\t\t<!--  Increments -->\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_15_sec_inc</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>0/15 * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_15_sec_inc_with_star</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>*/15 * * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_inc_2_fields</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>*/15 5/50 * * * ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\t\t\n\t\t<trigger>\n\t\t\t<cron>\n\t\t\t\t<name>every_inc_of_something</name>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<cron-expression>*/15 5/50 5/15 1/3 7/6 ?</cron-expression>\n\t\t\t</cron>\n\t\t</trigger>\n    <trigger>\n  \t\t\t<cron>\n  \t\t\t\t<name>QTZ-329</name>\n  \t\t\t\t<job-name>job1</job-name>\n          <cron-expression>0 0/30 0-6,12,19-21,22 * * ?</cron-expression>\n  \t\t\t</cron>\n  \t\t</trigger>\n\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/overwrite-no-jobclass.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\n    <processing-directives>\n        <overwrite-existing-data>true</overwrite-existing-data>\n        <ignore-duplicates>false</ignore-duplicates>\n    </processing-directives>\n\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<job-data-map>\n\t\t\t\t<entry><key>foo</key><value>bar</value></entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/quartz-test.properties",
    "content": "org.quartz.scheduler.instanceName: DefaultQuartzScheduler\norg.quartz.scheduler.rmi.export: false\norg.quartz.scheduler.rmi.proxy: false\norg.quartz.scheduler.wrapJobExecutionInUserTransaction: false\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 10\norg.quartz.threadPool.threadPriority: 5\norg.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/quartz-xml-plugin-test.properties",
    "content": "org.quartz.scheduler.instanceName: DefaultQuartzScheduler\norg.quartz.scheduler.rmi.export: false\norg.quartz.scheduler.rmi.proxy: false\norg.quartz.scheduler.wrapJobExecutionInUserTransaction: false\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 10\norg.quartz.threadPool.threadPriority: 5\norg.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n\norg.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin\norg.quartz.plugin.jobInitializer.fileNames = org/quartz/xml/simple-job-trigger-no-repeat.xml\norg.quartz.plugin.jobInitializer.failOnFileNotFound = true\n#org.quartz.plugin.jobInitializer.scanInterval = 5\n\n"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/simple-job-trigger-no-repeat.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\t\t\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<durability>true</durability>\n\t\t\t<recover>false</recover>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1_trigger</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/simple-job-trigger-with-timezones.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\t\t\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<durability>true</durability>\n\t\t\t<recover>false</recover>\n\t\t\t<job-data-map>\n\t\t\t\t<entry><key>foo</key><value>bar</value></entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<start-time>2012-01-01T18:00:00Z</start-time><!-- 18:00 UTC -->\n\t\t\t\t<end-time>2012-01-01T22:00:00+03:00</end-time><!-- 19:00 UTC -->\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job2</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<start-time>2012-01-01T06:00:00</start-time><!-- 6:00 localtime ! -->\n\t\t\t\t<end-time>2012-01-01T16:00:00-03:00</end-time><!-- 19:00 UTC -->\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/org/quartz/xml/simple-job-trigger.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<job-scheduling-data version=\"2.0\" xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\">\n\t\t\n\t<schedule>\n\t\t<job>\n\t\t\t<name>job1</name>\n\t\t\t<group>DEFAULT</group>\n\t\t\t<job-class>org.quartz.xml.XMLSchedulingDataProcessorTest$MyJob</job-class>\n\t\t\t<durability>true</durability>\n\t\t\t<recover>false</recover>\n\t\t\t<job-data-map>\n\t\t\t\t<entry><key>foo</key><value>bar</value></entry>\n\t\t\t</job-data-map>\n\t\t</job>\n\t\t<trigger>\n\t\t\t<simple>\n\t\t\t\t<name>job1</name>\n\t\t\t\t<group>DEFAULT</group>\n\t\t\t\t<job-name>job1</job-name>\n\t\t\t\t<job-group>DEFAULT</job-group>\n\t\t\t\t<repeat-count>-1</repeat-count>\n\t\t\t\t<repeat-interval>1500</repeat-interval>\n\t\t\t</simple>\n\t\t</trigger>\n\t\t\n\t</schedule>\n\t\n</job-scheduling-data>"
  },
  {
    "path": "quartz/src/test/resources/tables_derby_drop.sql",
    "content": "-- \n-- Apache Derby scripts by Steve Stewart, updated by Ronald Pomeroy\n-- Based on Srinivas Venkatarangaiah's file for Cloudscape\n-- \n-- Known to work with Apache Derby 10.0.2.1, or 10.6.2.1\n--\n-- Updated by Zemian Deng <saltnlight5@gmail.com> on 08/21/2011\n--   * Fixed nullable fields on qrtz_simprop_triggers table. \n--   * Added Derby QuickStart comments and drop tables statements.\n--\n-- DerbyDB + Quartz Quick Guide:\n-- * Derby comes with Oracle JDK! For Java6, it default install into C:/Program Files/Sun/JavaDB on Windows.\n-- 1. Create a derby.properties file under JavaDB directory, and have the following:\n--    derby.connection.requireAuthentication = true\n--    derby.authentication.provider = BUILTIN\n--    derby.user.quartz2=quartz2123\n-- 2. Start the DB server by running bin/startNetworkServer script.\n-- 3. On a new terminal, run bin/ij tool to bring up an SQL prompt, then run:\n--    connect 'jdbc:derby://localhost:1527/quartz2;user=quartz2;password=quartz2123;create=true';\n--    run 'quartz/docs/dbTables/tables_derby.sql';\n-- Now in quartz.properties, you may use these properties:\n--    org.quartz.dataSource.quartzDataSource.driver = org.apache.derby.jdbc.ClientDriver\n--    org.quartz.dataSource.quartzDataSource.URL = jdbc:derby://localhost:1527/quartz2\n--    org.quartz.dataSource.quartzDataSource.user = quartz2\n--    org.quartz.dataSource.quartzDataSource.password = quartz2123\n--\n\n-- Auto drop and reset tables \n-- Derby doesn't support if exists condition on table drop, so user must manually do this step if needed to.\ndrop table qrtz_fired_triggers;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_scheduler_state;\ndrop table qrtz_locks;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_calendars;\n\n"
  },
  {
    "path": "quartz-jobs/build.gradle",
    "content": "plugins {\n    id 'java-library'\n    id 'maven-publish'\n    id 'biz.aQute.bnd.builder'\n}\n\ndependencies {\n    implementation project(':quartz')\n\n    implementation \"org.slf4j:slf4j-api:$slf4jVersion\"\n    runtimeOnly \"org.slf4j:slf4j-log4j12:$slf4jVersion\"\n\n    compileOnly 'jakarta.jms:jakarta.jms-api:3.1.0'\n    compileOnly 'jakarta.mail:jakarta.mail-api:2.1.5'\n    compileOnly 'jakarta.ejb:jakarta.ejb-api:4.0.1'\n    compileOnly 'org.glassfish.corba:rmic:5.0.0'\n\n    testImplementation 'jakarta.transaction:jakarta.transaction-api:2.0.1'\n    testImplementation 'commons-io:commons-io:2.21.0'\n    testImplementation \"junit:junit:$junitVersion\"\n    testImplementation 'org.hamcrest:hamcrest-library:3.0'\n    testImplementation 'jakarta.mail:jakarta.mail-api:2.1.5'\n\n    testImplementation 'org.subethamail:subethasmtp:3.1.7'\n}\n\njava {\n    withJavadocJar()\n    withSourcesJar()\n}\n\ntest {\n    maxParallelForks 1\n    forkEvery 1\n}\n\npublishing {\n    publications {\n        getByName('maven').pom.description = 'Quartz Enterprise Job Scheduler - additional library of ready to use Jobs'\n    }\n}"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/DirectoryScanJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\nimport java.io.File;\nimport java.io.FileFilter;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Inspects a directory and compares whether any files' \"last modified dates\" \n * have changed since the last time it was inspected.  If one or more files \n * have been updated (or created), the job invokes a \"call-back\" method on an \n * identified <code>DirectoryScanListener</code> that can be found in the \n * <code>SchedulerContext</code>.\n * \n * @author pl47ypus\n * @author jhouse\n * @see org.quartz.jobs.DirectoryScanListener\n * @see org.quartz.SchedulerContext\n */\n@DisallowConcurrentExecution\n@PersistJobDataAfterExecution\npublic class DirectoryScanJob implements Job {\n\n    /**\n     * <code>JobDataMap</code> key with which to specify the directory to be \n     * monitored - an absolute path is recommended. \n     */\n    public static final String DIRECTORY_NAME = \"DIRECTORY_NAME\";\n\n    /**\n     * <code>JobDataMap</code> key with which to specify the \n     * {@link org.quartz.jobs.DirectoryScanListener} to be \n     * notified when the directory contents change.  \n     */\n    public static final String DIRECTORY_SCAN_LISTENER_NAME = \"DIRECTORY_SCAN_LISTENER_NAME\";\n\n    /**\n     * <code>JobDataMap</code> key with which to specify a <code>long</code>\n     * value that represents the minimum number of milliseconds that must have\n     * past since the file's last modified time in order to consider the file\n     * new/altered.  This is necessary because another process may still be\n     * in the middle of writing to the file when the scan occurs, and the\n     * file may therefore not yet be ready for processing.\n     * \n     * <p>If this parameter is not specified, a default value of \n     * <code>5000</code> (five seconds) will be used.</p>\n     */\n    public static final String MINIMUM_UPDATE_AGE = \"MINIMUM_UPDATE_AGE\";\n\n    private static final String LAST_MODIFIED_TIME = \"LAST_MODIFIED_TIME\";\n    \n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    public DirectoryScanJob() {\n    }\n\n    /** \n     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)\n     */\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();\n        SchedulerContext schedCtx = null;\n        try {\n            schedCtx = context.getScheduler().getContext();\n        } catch (SchedulerException e) {\n            throw new JobExecutionException(\"Error obtaining scheduler context.\", e, false);\n        }\n        \n        String dirName = mergedJobDataMap.getString(DIRECTORY_NAME);\n        String listenerName = mergedJobDataMap.getString(DIRECTORY_SCAN_LISTENER_NAME);\n        \n        if(dirName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    DIRECTORY_NAME + \"' not found in merged JobDataMap\");\n        }\n        if(listenerName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    DIRECTORY_SCAN_LISTENER_NAME + \"' not found in merged JobDataMap\");\n        }\n\n        DirectoryScanListener listener = (DirectoryScanListener)schedCtx.get(listenerName);\n        \n        if(listener == null) {\n            throw new JobExecutionException(\"DirectoryScanListener named '\" + \n                    listenerName + \"' not found in SchedulerContext\");\n        }\n        \n        long lastDate = -1;\n        if(mergedJobDataMap.containsKey(LAST_MODIFIED_TIME)) {\n            lastDate = mergedJobDataMap.getLong(LAST_MODIFIED_TIME);\n        }\n        \n        long minAge = 5000;\n        if(mergedJobDataMap.containsKey(MINIMUM_UPDATE_AGE)) {\n            minAge = mergedJobDataMap.getLong(MINIMUM_UPDATE_AGE);\n        }\n        long maxAgeDate = System.currentTimeMillis() - minAge;\n        \n        File[] updatedFiles = getUpdatedOrNewFiles(dirName, lastDate, maxAgeDate);\n\n        if(updatedFiles == null) {\n            log.warn(\"Directory '\"+dirName+\"' does not exist.\");\n            return;\n        }\n        \n        long latestMod = lastDate;\n        for(File updFile: updatedFiles) {\n            long lm = updFile.lastModified();\n            latestMod = (lm > latestMod) ? lm : latestMod;\n        }\n        \n        if(updatedFiles.length > 0) {\n            // notify call back...\n            log.info(\"Directory '\"+dirName+\"' contents updated, notifying listener.\");\n            listener.filesUpdatedOrAdded(updatedFiles); \n        } else if (log.isDebugEnabled()) {\n            log.debug(\"Directory '\"+dirName+\"' contents unchanged.\");\n        }\n        \n        // It is the JobDataMap on the JobDetail which is actually stateful\n        context.getJobDetail().getJobDataMap().put(LAST_MODIFIED_TIME, latestMod);\n    }\n    \n    protected File[] getUpdatedOrNewFiles(String dirName, final long lastDate, final long maxAgeDate) {\n\n        File dir = new File(dirName);\n        if(!dir.exists() || !dir.isDirectory()) {\n            return null;\n        } \n        \n        File[] files = dir.listFiles(new FileFilter() {\n\n            public boolean accept(File pathname) {\n                if(pathname.lastModified() > lastDate && pathname.lastModified() < maxAgeDate)\n                    return true;\n                return false;\n            }});\n\n        if(files == null)\n            files = new File[0];\n        \n        return files;\n    }\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/DirectoryScanListener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\nimport java.io.File;\n\n/**\n * Interface for objects wishing to receive a 'call-back' from a \n * <code>DirectoryScanJob</code>.\n * \n * <p>Instances should be stored in the {@link org.quartz.SchedulerContext} \n * such that the <code>DirectoryScanJob</code> can find it.</p>\n * \n * @author jhouse\n * @see org.quartz.jobs.DirectoryScanJob\n * @see org.quartz.SchedulerContext\n */\npublic interface DirectoryScanListener {\n\n    /**\n     * @param updatedFiles The set of files that were updated/added since the\n     * last scan of the directory\n     */\n    void filesUpdatedOrAdded(File[] updatedFiles);\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/FileScanJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.net.URLDecoder;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.quartz.PersistJobDataAfterExecution;\nimport org.quartz.SchedulerContext;\nimport org.quartz.SchedulerException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Inspects a file and compares whether it's \"last modified date\" has changed\n * since the last time it was inspected.  If the file has been updated, the\n * job invokes a \"call-back\" method on an identified \n * <code>FileScanListener</code> that can be found in the \n * <code>SchedulerContext</code>.\n * \n * @author jhouse\n * @author pl47ypus\n * @see org.quartz.jobs.FileScanListener\n */\n@DisallowConcurrentExecution\n@PersistJobDataAfterExecution\npublic class FileScanJob implements Job {\n\n    /**\n     * <code>JobDataMap</code> key with which to specify \n     * the name of the file to monitor.\n     */\n    public static final String FILE_NAME = \"FILE_NAME\";\n    \n    /**\n     * <code>JobDataMap</code> key with which to specify the \n     * {@link org.quartz.jobs.FileScanListener} to be \n     * notified when the file contents change.  \n     */\n    public static final String FILE_SCAN_LISTENER_NAME = \"FILE_SCAN_LISTENER_NAME\";\n    \n    /**\n     * <code>JobDataMap</code> key with which to specify a <code>long</code>\n     * value that represents the minimum number of milliseconds that must have\n     * past since the file's last modified time in order to consider the file\n     * new/altered.  This is necessary because another process may still be\n     * in the middle of writing to the file when the scan occurs, and the\n     * file may therefore not yet be ready for processing.\n     * \n     * <p>If this parameter is not specified, a default value of \n     * <code>5000</code> (five seconds) will be used.</p>\n     */\n    public static final String MINIMUM_UPDATE_AGE = \"MINIMUM_UPDATE_AGE\";\n\n    private static final String LAST_MODIFIED_TIME = \"LAST_MODIFIED_TIME\";\n    \n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    public FileScanJob() {\n    }\n\n    /** \n     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)\n     */\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();\n        SchedulerContext schedCtx = null;\n        try {\n            schedCtx = context.getScheduler().getContext();\n        } catch (SchedulerException e) {\n            throw new JobExecutionException(\"Error obtaining scheduler context.\", e, false);\n        }\n        \n        String fileName = mergedJobDataMap.getString(FILE_NAME);\n        String listenerName = mergedJobDataMap.getString(FILE_SCAN_LISTENER_NAME);\n        \n        if(fileName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    FILE_NAME + \"' not found in merged JobDataMap\");\n        }\n        if(listenerName == null) {\n            throw new JobExecutionException(\"Required parameter '\" + \n                    FILE_SCAN_LISTENER_NAME + \"' not found in merged JobDataMap\");\n        }\n\n        FileScanListener listener = (FileScanListener)schedCtx.get(listenerName);\n        \n        if(listener == null) {\n            throw new JobExecutionException(\"FileScanListener named '\" + \n                    listenerName + \"' not found in SchedulerContext\");\n        }\n        \n        long lastDate = -1;\n        if(mergedJobDataMap.containsKey(LAST_MODIFIED_TIME)) {\n            lastDate = mergedJobDataMap.getLong(LAST_MODIFIED_TIME);\n        }\n\n        long minAge = 5000;\n        if(mergedJobDataMap.containsKey(MINIMUM_UPDATE_AGE)) {\n            minAge = mergedJobDataMap.getLong(MINIMUM_UPDATE_AGE);\n        }\n        long maxAgeDate = System.currentTimeMillis() + minAge;\n        \n        \n        long newDate = getLastModifiedDate(fileName);\n        \n        if(newDate < 0) {\n            log.warn(\"File '\"+fileName+\"' does not exist.\");\n            return;\n        }\n        \n        if(lastDate > 0 && (newDate > lastDate && newDate < maxAgeDate)) {\n            // notify call back...\n            log.info(\"File '\"+fileName+\"' updated, notifying listener.\");\n            listener.fileUpdated(fileName); \n        } else if (log.isDebugEnabled()) {\n            log.debug(\"File '\"+fileName+\"' unchanged.\");\n        }\n        \n        // It is the JobDataMap on the JobDetail which is actually stateful\n        context.getJobDetail().getJobDataMap().put(LAST_MODIFIED_TIME, newDate);\n    }\n    \n    protected long getLastModifiedDate(String fileName) {\n        URL resource = Thread.currentThread().getContextClassLoader().getResource(fileName);\n        \n        // Get the absolute path.\n        String filePath = (resource == null) ? fileName : URLDecoder.decode(resource.getFile()); ;\n        \n        // If the jobs file is inside a jar point to the jar file (to get it modification date).\n        // Otherwise continue as usual.\n        int jarIndicator = filePath.indexOf('!');\n        \n        if (jarIndicator > 0) {\n            filePath = filePath.substring(5, filePath.indexOf('!'));\n        }\n\n        File file = new File(filePath);\n        \n        if(!file.exists()) {\n            return -1;\n        } else {\n            return file.lastModified();\n        }\n    }\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/FileScanListener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\n/**\n * Interface for objects wishing to receive a 'call-back' from a \n * <code>FileScanJob</code>.\n * \n * @author jhouse\n * @see org.quartz.jobs.FileScanJob\n */\npublic interface FileScanListener {\n\n    void fileUpdated(String fileName);\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/NoOpJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * An implementation of Job, that does absolutely nothing - useful for system\n * which only wish to use <code>{@link org.quartz.TriggerListener}s</code>\n * and <code>{@link org.quartz.JobListener}s</code>, rather than writing\n * Jobs that perform work.\n * </p>\n * \n * @author James House\n */\npublic class NoOpJob implements Job {\n\n\n    /*\n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Constructors.\n     *  \n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n    \n    public NoOpJob() {\n    }\n\n    /*\n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     *\n     * Interface.\n     *  \n     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * <p>\n     * Do nothing.\n     * </p>\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n    }\n    \n}"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/ejb/EJB3InvokerJob.java",
    "content": "package org.quartz.jobs.ee.ejb;\n\nimport java.lang.reflect.InvocationTargetException;\n\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\n\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * A <code>Job</code> that invokes a method on an EJB3.\n * </p>\n * \n * Expects the properties corresponding to the following keys to be in the\n * <code>JobDataMap</code> when it executes:\n * <ul>\n * <li><code>EJB_JNDI_NAME_KEY</code>- the JNDI name (location) of the EJB's\n * home interface.</li>\n * <li><code>EJB_METHOD_KEY</code>- the name of the method to invoke on the EJB.\n * </li>\n * <li><code>EJB_ARGS_KEY</code>- an Object[] of the args to pass to the method\n * (optional, if left out, there are no arguments).</li>\n * <li><code>EJB_ARG_TYPES_KEY</code>- an Class[] of the types of the args to\n * pass to the method (optional, if left out, the types will be derived by\n * calling getClass() on each of the arguments).</li>\n * </ul>\n * <br>\n * The following keys can also be used at need:\n * <ul>\n * <li><code>INITIAL_CONTEXT_FACTORY</code> - the context factory used to build\n * the context.</li>\n * <li><code>PROVIDER_URL</code> - the name of the environment property for\n * specifying configuration information for the service provider to use.</li>\n * </ul>\n * \n * <p>\n * The result of the EJB method invocation will be available to\n * <code>Job/TriggerListener</code>s via\n * <code>{@link org.quartz.JobExecutionContext#getResult()}</code>.\n * </p>\n * \n * @author hhuynh\n * @see org.quartz.jobs.ee.ejb.EJBInvokerJob\n */\npublic class EJB3InvokerJob extends EJBInvokerJob {\n\n    @Override\n    public void execute(JobExecutionContext context)\n            throws JobExecutionException {\n        JobDataMap dataMap = context.getMergedJobDataMap();\n\n        String ejb = dataMap.getString(EJB_JNDI_NAME_KEY);\n        String method = dataMap.getString(EJB_METHOD_KEY);\n\n        Object[] arguments = (Object[]) dataMap.get(EJB_ARGS_KEY);\n        if (arguments == null) {\n            arguments = new Object[0];\n        }\n        if (ejb == null) {\n            throw new JobExecutionException(\"must specify EJB_JNDI_NAME_KEY\");\n        }\n        if (method == null) {\n            throw new JobExecutionException(\"must specify EJB_METHOD_KEY\");\n        }\n\n        InitialContext jndiContext = null;\n        Object value = null;\n        try {\n            try {\n                jndiContext = getInitialContext(dataMap);\n                value = jndiContext.lookup(ejb);\n            } catch (NamingException ne) {\n                throw new JobExecutionException(ne);\n            }\n            \n            Class<?>[] argTypes = (Class[]) dataMap.get(EJB_ARG_TYPES_KEY);\n            if (argTypes == null) {\n                argTypes = new Class[arguments.length];\n                for (int i = 0; i < arguments.length; i++) {\n                    argTypes[i] = arguments[i].getClass();\n                }\n            }\n\n            try {\n                Object returnValue = value.getClass()\n                        .getMethod(method, argTypes).invoke(value, arguments);\n                context.setResult(returnValue);\n            } catch (IllegalAccessException iae) {\n                throw new JobExecutionException(iae);\n            } catch (InvocationTargetException ite) {\n                throw new JobExecutionException(ite.getTargetException());\n            } catch (NoSuchMethodException nsme) {\n                throw new JobExecutionException(nsme);\n            }\n        } finally {\n            if (jndiContext != null) {\n                try {\n                    jndiContext.close();\n                } catch (Exception e) {\n                    // ignored\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/ejb/EJBInvokerJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.ejb;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.rmi.RemoteException;\nimport java.util.Hashtable;\n\nimport jakarta.ejb.EJBHome;\nimport jakarta.ejb.EJBMetaData;\nimport jakarta.ejb.EJBObject;\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport javax.rmi.PortableRemoteObject;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * A <code>Job</code> that invokes a method on an EJB.\n * </p>\n * \n * Expects the properties corresponding to the following keys to be in the\n * <code>JobDataMap</code> when it executes:\n * <ul>\n * <li><code>EJB_JNDI_NAME_KEY</code>- the JNDI name (location) of the\n * EJB's home interface.</li>\n * <li><code>EJB_METHOD_KEY</code>- the name of the method to invoke on the\n * EJB.</li>\n * <li><code>EJB_ARGS_KEY</code>- an Object[] of the args to pass to the\n * method (optional, if left out, there are no arguments).</li>\n * <li><code>EJB_ARG_TYPES_KEY</code>- an Class[] of the types of the args to \n * pass to the method (optional, if left out, the types will be derived by \n * calling getClass() on each of the arguments).</li>\n * </ul>\n * <br>\n * The following keys can also be used at need:\n * <ul>\n * <li><code>INITIAL_CONTEXT_FACTORY</code> - the context factory used to \n * build the context.</li>\n * <li><code>PROVIDER_URL</code> - the name of the environment property\n * for specifying configuration information for the service provider to use.\n * </li>\n * </ul>\n * \n * <p>\n * The result of the EJB method invocation will be available to \n * <code>Job/TriggerListener</code>s via\n * <code>{@link org.quartz.JobExecutionContext#getResult()}</code>.\n * </p>\n * \n * @author Andrew Collins\n * @author James House\n * @author Joel Shellman\n * @author <a href=\"mailto:bonhamcm@thirdeyeconsulting.com\">Chris Bonham</a>\n */\npublic class EJBInvokerJob implements Job {\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public static final String EJB_JNDI_NAME_KEY = \"ejb\";\n\n    public static final String EJB_METHOD_KEY = \"method\";\n\n    public static final String EJB_ARG_TYPES_KEY = \"argTypes\";\n\n    public static final String EJB_ARGS_KEY = \"args\";\n    \n    public static final String INITIAL_CONTEXT_FACTORY = \"java.naming.factory.initial\";\n    \n    public static final String PROVIDER_URL = \"java.naming.provider.url\";\n\n    public static final String PRINCIPAL = \"java.naming.security.principal\";\n\n    public static final String CREDENTIALS = \"java.naming.security.credentials\";\n\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constructors.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public EJBInvokerJob() {\n        // nothing\n    }\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n        JobDataMap dataMap = context.getMergedJobDataMap();\n\n        String ejb = dataMap.getString(EJB_JNDI_NAME_KEY);\n        String method = dataMap.getString(EJB_METHOD_KEY);\n        Object[] arguments = (Object[]) dataMap.get(EJB_ARGS_KEY);\n        if (arguments == null) {\n            arguments = new Object[0];\n        }\n\n        if (ejb == null) { \n            // must specify remote home\n            throw new JobExecutionException(); \n        }\n\n        InitialContext jndiContext = null;\n\n        // get initial context\n        try {\n            jndiContext = getInitialContext(dataMap);\n        } catch (NamingException ne) {\n            throw new JobExecutionException(ne);\n        }\n             \n        try {\n            Object value = null;\n            \n            // locate home interface\n            try {\n                value = jndiContext.lookup(ejb);\n            } catch (NamingException ne) {\n                throw new JobExecutionException(ne);\n            } \n    \n            // get home interface\n            EJBHome ejbHome = (EJBHome) PortableRemoteObject.narrow(value,\n                    EJBHome.class);\n    \n            // get meta data\n            EJBMetaData metaData = null;\n    \n            try {\n                metaData = ejbHome.getEJBMetaData();\n            } catch (RemoteException re) {\n                throw new JobExecutionException(re);\n            }\n    \n            // get home interface class\n            Class<?> homeClass = metaData.getHomeInterfaceClass();\n    \n            // get remote interface class\n            Class<?> remoteClass = metaData.getRemoteInterfaceClass();\n    \n            // get home interface\n            ejbHome = (EJBHome) PortableRemoteObject.narrow(ejbHome, homeClass);\n    \n            Method methodCreate = null;\n    \n            try {\n                // create method 'create()' on home interface\n                methodCreate = homeClass.getMethod(\"create\", ((Class[])null));\n            } catch (NoSuchMethodException nsme) {\n                throw new JobExecutionException(nsme);\n            }\n    \n            // create remote object\n            EJBObject remoteObj = null;\n    \n            try {\n                // invoke 'create()' method on home interface\n                remoteObj = (EJBObject) methodCreate.invoke(ejbHome, ((Object[])null));\n            } catch (IllegalAccessException iae) {\n                throw new JobExecutionException(iae);\n            } catch (InvocationTargetException ite) {\n                throw new JobExecutionException(ite);\n            }\n    \n            // execute user-specified method on remote object\n            Method methodExecute = null;\n    \n            try {\n                // create method signature\n    \n                Class<?>[] argTypes = (Class[]) dataMap.get(EJB_ARG_TYPES_KEY);\n                if (argTypes == null) {\n                    argTypes = new Class[arguments.length];\n                    for (int i = 0; i < arguments.length; i++) {\n                        argTypes[i] = arguments[i].getClass();\n                    }\n                }\n    \n                // get method on remote object\n                methodExecute = remoteClass.getMethod(method, argTypes);\n            } catch (NoSuchMethodException nsme) {\n                throw new JobExecutionException(nsme);\n            }\n    \n            try {\n                // invoke user-specified method on remote object\n                Object returnObj = methodExecute.invoke(remoteObj, arguments);\n                \n                // Return any result in the JobExecutionContext so it will be \n                // available to Job/TriggerListeners\n                context.setResult(returnObj);\n            } catch (IllegalAccessException iae) {\n                throw new JobExecutionException(iae);\n            } catch (InvocationTargetException ite) {\n                throw new JobExecutionException(ite);\n            }\n        } finally {\n            // Don't close jndiContext until after method execution because\n            // WebLogic requires context to be open to keep the user credentials\n            // available.  See Jira Issue: QUARTZ-401\n            if (jndiContext != null) {\n                try {\n                    jndiContext.close();\n                } catch (NamingException e) {\n                    // Ignore any errors closing the initial context\n                }\n            }\n        }\n    }\n\n    protected InitialContext getInitialContext(JobDataMap jobDataMap)\n        throws NamingException {\n        Hashtable<String, String> params = new Hashtable<String, String>(2);\n        \n        String initialContextFactory =\n            jobDataMap.getString(INITIAL_CONTEXT_FACTORY);\n        if (initialContextFactory != null) {\n            params.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);\n        }\n        \n        String providerUrl = jobDataMap.getString(PROVIDER_URL);\n        if (providerUrl != null) {\n            params.put(Context.PROVIDER_URL, providerUrl);\n        }\n\n        String principal = jobDataMap.getString(PRINCIPAL);\n        if ( principal != null ) {\n            params.put( Context.SECURITY_PRINCIPAL, principal );\n        }\n\n        String credentials = jobDataMap.getString(CREDENTIALS);\n        if ( credentials != null ) {\n            params.put( Context.SECURITY_CREDENTIALS, credentials );\n        }\n\n        return (params.size() == 0) ? new InitialContext() : new InitialContext(params);\n    }    \n}"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/JmsHelper.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport java.lang.reflect.Method;\nimport java.util.Hashtable;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\n\nimport org.quartz.JobDataMap;\n\n/**\n * Utility class that aids in the processing of JMS based jobs and sending of\n * <code>jakarta.jms.Message</code>\n * \n * @author Fernando Ribeiro\n * @author Weston M. Price\n */\npublic final class JmsHelper {\n    public static final String CREDENTIALS = \"java.naming.security.credentials\";\n\n    public static final String INITIAL_CONTEXT_FACTORY = \"java.naming.factory.initial\";\n\n    public static final String JMS_ACK_MODE = \"jms.acknowledge\";\n\n    public static final String JMS_CONNECTION_FACTORY_JNDI = \"jms.connection.factory\";\n\n    public static final String JMS_DESTINATION_JNDI = \"jms.destination\";\n\n    public static final String JMS_MSG_FACTORY_CLASS_NAME = \"jms.message.factory.class.name\";\n\n    public static final String JMS_PASSWORD = \"jms.password\";\n\n    public static final String JMS_USE_TXN = \"jms.use.transaction\";\n\n    public static final String JMS_USER = \"jms.user\";\n\n    public static final String PRINCIPAL = \"java.naming.security.principal\";\n\n    public static final String PROVIDER_URL = \"java.naming.provider.url\";\n\n    public static void closeResource(final Object resource) {\n\n        if (resource == null)\n            return;\n\n        try {\n            final Method m = resource.getClass().getMethod(\"close\",\n                    new Class[0]);\n\n            m.invoke(resource, new Object[0]);\n        } catch (final Exception e) {\n        }\n\n    }\n\n    public static InitialContext getInitialContext(final JobDataMap dataMap)\n            throws NamingException {\n        final Hashtable<String, String> params = new Hashtable<String, String>(4);\n\n        final String initialContextFactory = dataMap\n                .getString(INITIAL_CONTEXT_FACTORY);\n\n        if (initialContextFactory != null)\n            params.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);\n\n        final String providerUrl = dataMap.getString(PROVIDER_URL);\n\n        if (providerUrl != null)\n            params.put(Context.PROVIDER_URL, providerUrl);\n\n        final String principal = dataMap.getString(PRINCIPAL);\n\n        if (principal != null)\n            params.put(Context.SECURITY_PRINCIPAL, principal);\n\n        final String credentials = dataMap.getString(CREDENTIALS);\n\n        if (credentials != null)\n            params.put(Context.SECURITY_CREDENTIALS, credentials);\n\n        if (params.size() == 0)\n            return new InitialContext();\n        else\n            return new InitialContext(params);\n\n    }\n\n    public static JmsMessageFactory getMessageFactory(final String name)\n            throws JmsJobException {\n\n        try {\n            final Class<?> cls = Class.forName(name);\n\n            final JmsMessageFactory factory = (JmsMessageFactory) cls\n                    .newInstance();\n\n            return factory;\n        } catch (final Exception e) {\n            throw new JmsJobException(e.getMessage(), e);\n        }\n\n    }\n\n    public static boolean isDestinationSecure(final JobDataMap dataMap) {\n        return ((dataMap.getString(JmsHelper.JMS_USER) != null) && (dataMap\n                .getString(JmsHelper.JMS_PASSWORD) != null));\n    }\n\n    public static boolean useTransaction(final JobDataMap dataMap) {\n        return dataMap.getBoolean(JMS_USE_TXN);\n    }\n\n    private JmsHelper() {\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/JmsJobException.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport org.quartz.SchedulerException;\n\n/**\n * The JmsJobException is used to indicate an error during sending of a\n * <code>jakarta.jms.Message</code>.\n * \n * @author Fernando Ribeiro\n * @author Weston M. Price\n */\npublic final class JmsJobException extends SchedulerException {\n    private static final long serialVersionUID = 3045647075496522093L;\n\n    public JmsJobException(final String message) {\n        super(message);\n    }\n\n    public JmsJobException(final String message, final Throwable cause) {\n        super(message, cause);\n    }\n\n    public JmsJobException(final Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/JmsMessageFactory.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport jakarta.jms.Message;\nimport jakarta.jms.Session;\n\nimport org.quartz.JobDataMap;\n\n/**\n * The JmsMessageFactory interface allows for the creation of a\n * <code>jakarta.jms.Message</code>. This interface is used in constructing a\n * <code>jakarta.jms.Message</code> that is to be sent upon execution of a JMS\n * enabled job.\n * \n * @see SendDestinationMessageJob\n * @see SendQueueMessageJob\n * @see SendTopicMessageJob\n * \n * @author Weston M. Price\n */\npublic interface JmsMessageFactory {\n\n    /**\n     * Creates a <code>jakarta.jms.Message</code>.\n     * \n     * @param jobDataMap\n     *            the <code>JobDataMap</code>\n     * @param session\n     *            the <code>jakarta.jms.Session</code>\n     * \n     * @return the <code>jakarta.jms.Message</code>\n     */\n    Message createMessage(JobDataMap jobDataMap, Session session);\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/SendDestinationMessageJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport jakarta.jms.Connection;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.Destination;\nimport jakarta.jms.Message;\nimport jakarta.jms.MessageProducer;\nimport jakarta.jms.Session;\nimport javax.naming.Context;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * A <code>Job</code> that sends a <code>jakarta.jms.Message</code> to a\n * <code>jakarta.jms.Destination</code>. Note, this class can only be used in a\n * JMS-based environment.\n * \n * <p>\n * The following properties are expected to be provided in the\n * <code>JobDataMap</code>:\n * \n * <ul>\n * <li><code>JMS_CONNECTION_FACTORY_JNDI</code> - The JNDI name of the JMS\n * Connection Factory.</li>\n * <li><code>JMS_DESTINATION_JNDI</code> - The JNDI name of the JMS\n * destination.</li>\n * <li><code>JMS_USE_TXN</code> - Whether or not to use a transacted\n * <code>jakarta.jms.Session</code>.</li>\n * <li><code>JMS_ACK_MODE</code> - The acknowledgement mode for the\n * <code>jakarta.jms.Session</code>.</li>\n * <li><code>JMS_MSG_FACTORY_CLASS_NAME</code> - The implementation class\n * name for the <code>JmsMessageFactory</code>.</li>\n * </ul>\n * \n * <p>\n * The following properties are optional\n * \n * <ul>\n * <li><code>JMS_USER</code> - The JMS user for secure destinations.\n * <li><code>JMS_PASSWORD</code> - The JMS password for secure destinations.\n * </ul>\n * \n * <p>\n * The following properties can be used for JNDI support:\n * \n * <ul>\n * <li><code>INITIAL_CONTEXT_FACTORY</code> - The java.naming.factory.initial\n * setting for JNDI.\n * <li><code>PROVIDER_URL</code> - The java.naming.provider.url for JNDI.\n * </ul>\n * \n * @see JmsMessageFactory\n * \n * @author Fernando Ribeiro\n * @author Weston M. Price\n * @author Frank Van Uffelen\n */\npublic final class SendDestinationMessageJob implements Job {\n\n    public void execute(final JobExecutionContext jobCtx)\n            throws JobExecutionException {\n        Connection conn = null;\n\n        Session sess = null;\n\n        MessageProducer producer = null;\n\n        try {\n            final JobDataMap dataMap = jobCtx.getMergedJobDataMap();\n\n            final Context namingCtx = JmsHelper.getInitialContext(dataMap);\n\n            final ConnectionFactory connFactory = (ConnectionFactory) namingCtx\n                    .lookup(dataMap\n                            .getString(JmsHelper.JMS_CONNECTION_FACTORY_JNDI));\n\n            if (!JmsHelper.isDestinationSecure(dataMap)) {\n                conn = connFactory.createConnection();\n            } else {\n                final String user = dataMap.getString(JmsHelper.JMS_USER);\n\n                final String password = dataMap\n                        .getString(JmsHelper.JMS_PASSWORD);\n\n                conn = connFactory.createConnection(user, password);\n            }\n\n            final boolean useTransaction = JmsHelper.useTransaction(dataMap);\n\n            final int ackMode = dataMap.getInt(JmsHelper.JMS_ACK_MODE);\n\n            sess = conn.createSession(useTransaction, ackMode);\n\n            final Destination destination = (Destination) namingCtx\n                    .lookup(dataMap.getString(JmsHelper.JMS_DESTINATION_JNDI));\n\n            producer = sess.createProducer(destination);\n\n            final JmsMessageFactory messageFactory = JmsHelper\n                    .getMessageFactory(dataMap\n                            .getString(JmsHelper.JMS_MSG_FACTORY_CLASS_NAME));\n\n            final Message msg = messageFactory.createMessage(dataMap, sess);\n\n            producer.send(msg);\n        } catch (final Exception e) {\n            throw new JobExecutionException(e);\n        } finally {\n            JmsHelper.closeResource(producer);\n\n            JmsHelper.closeResource(sess);\n\n            JmsHelper.closeResource(conn);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/SendQueueMessageJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport jakarta.jms.Message;\nimport jakarta.jms.Queue;\nimport jakarta.jms.QueueConnection;\nimport jakarta.jms.QueueConnectionFactory;\nimport jakarta.jms.QueueSender;\nimport jakarta.jms.QueueSession;\nimport javax.naming.Context;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n* <p>\n* A <code>Job</code> that sends a <code>jakarta.jms.Message</code> to a \n* <code>jakarta.jms.Queue</code>. This class is for older JMS. If you are using\n * JMS 1.1, you should use {@link SendDestinationMessageJob} instead.\n* \n* <p>\n* The following properties are expected to be provided in the <code>JobDataMap</code>:\n* \n* <ul>\n* <li><code>JMS_CONNECTION_FACTORY_JNDI</code> - The JNDI name of the JMS Connection Factory.</li>\n* <li><code>JMS_DESTINATION_JNDI</code> - The JNDI name of the JMS destination.</li>\n* <li><code>JMS_USE_TXN</code> - Whether or not to use a transacted <code>jakarta.jms.Session</code>.</li>\n* <li><code>JMS_ACK_MODE</code> - The acknowledgement mode for the <code>jakarta.jms.Session</code>.</li>\n* <li><code>JMS_MSG_FACTORY_CLASS_NAME</code> - The implementation class name for the <code>JmsMessageFactory</code>.</li>\n* </ul>\n* \n* <p>\n* The following properties are optional\n* \n* <ul>\n* <li><code>JMS_USER</code> - The JMS user for secure destinations.\n* <li><code>JMS_PASSWORD</code> - The JMS password for secure destinations.\n* </ul>\n* \n* <p>\n* The following properties can be used for JNDI support:\n* <ul>\n* <li><code>INITIAL_CONTEXT_FACTORY</code> - The java.naming.factory.initial setting for JNDI.\n* <li><code>PROVIDER_URL</code> - The java.naming.provider.url for JNDI.\n* </ul>\n* \n* \n* @see JmsMessageFactory\n* \n* @author Weston M. Price (little fixes v. in 1.6.0 by Toni Alatalo) \n* \n*\n*/\npublic final class SendQueueMessageJob implements Job {\n\n    public void execute(final JobExecutionContext jobCtx)\n            throws JobExecutionException {\n        QueueConnection conn = null;\n\n        QueueSession sess = null;\n\n        QueueSender sender = null;\n\n        try {\n            final JobDataMap dataMap = jobCtx.getMergedJobDataMap();\n\n            final Context namingCtx = JmsHelper.getInitialContext(dataMap);\n\n            final QueueConnectionFactory connFactory = (QueueConnectionFactory) namingCtx\n                    .lookup(dataMap\n                            .getString(JmsHelper.JMS_CONNECTION_FACTORY_JNDI));\n\n            if (!JmsHelper.isDestinationSecure(dataMap)) {\n                conn = connFactory.createQueueConnection();\n            } else {\n                final String user = dataMap.getString(JmsHelper.JMS_USER);\n\n                final String password = dataMap\n                        .getString(JmsHelper.JMS_PASSWORD);\n\n                conn = connFactory.createQueueConnection(user, password);\n            }\n\n            final boolean useTransactions = JmsHelper.useTransaction(dataMap);\n\n            final int ackMode = dataMap.getInt(JmsHelper.JMS_ACK_MODE);\n\n            sess = conn.createQueueSession(useTransactions, ackMode);\n\n            final Queue queue = (Queue) namingCtx.lookup(dataMap\n                    .getString(JmsHelper.JMS_DESTINATION_JNDI));\n\n            sender = sess.createSender(queue);\n\n            final JmsMessageFactory msgFactory = JmsHelper\n                    .getMessageFactory(dataMap\n                            .getString(JmsHelper.JMS_MSG_FACTORY_CLASS_NAME));\n\n            final Message msg = msgFactory.createMessage(dataMap, sess);\n\n            sender.send(msg);\n        } catch (final Exception e) {\n            throw new JobExecutionException(e.getMessage());\n        } finally {\n            JmsHelper.closeResource(sender);\n\n            JmsHelper.closeResource(sess);\n\n            JmsHelper.closeResource(conn);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jms/SendTopicMessageJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jms;\n\nimport jakarta.jms.Message;\nimport jakarta.jms.Topic;\nimport jakarta.jms.TopicConnection;\nimport jakarta.jms.TopicConnectionFactory;\nimport jakarta.jms.TopicPublisher;\nimport jakarta.jms.TopicSession;\nimport javax.naming.Context;\n\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * A <code>Job</code> that sends a <code>jakarta.jms.Message</code> to a\n * <code>jakarta.jms.Topic</code>. This class is for older JMS. If you are using\n * JMS 1.1, you should use {@link SendDestinationMessageJob} instead.\n * \n * <p>\n * The following properties are expected to be provided in the\n * <code>JobDataMap</code>:\n * \n * <ul>\n * <li><code>JMS_CONNECTION_FACTORY_JNDI</code> - The JNDI name of the JMS\n * Connection Factory.</li>\n * <li><code>JMS_DESTINATION_JNDI</code> - The JNDI name of the JMS\n * destination.</li>\n * <li><code>JMS_USE_TXN</code> - Whether or not to use a transacted\n * <code>jakarta.jms.Session</code>.</li>\n * <li><code>JMS_ACK_MODE</code> - The acknowledgment mode for the\n * <code>jakarta.jms.Session</code>.</li>\n * <li><code>JMS_MSG_FACTORY_CLASS_NAME</code> - The implementation class\n * name for the <code>JmsMessageFactory</code>.</li>\n * </ul>\n * \n * <p>\n * The following properties are optional\n * \n * <ul>\n * <li><code>JMS_USER</code> - The JMS user for secure destinations.\n * <li><code>JMS_PASSWORD</code> - The JMS password for secure destinations.\n * </ul>\n * \n * <p>\n * The following properties can be used for JNDI support:\n * \n * <ul>\n * <li><code>INITIAL_CONTEXT_FACTORY</code> - The java.naming.factory.initial\n * setting for JNDI.\n * <li><code>PROVIDER_URL</code> - The java.naming.provider.url for JNDI.\n * </ul>\n * \n * @see JmsMessageFactory\n * \n * @author Fernando Ribeiro\n * @author Weston M. Price\n */\npublic final class SendTopicMessageJob implements Job {\n\n    public void execute(final JobExecutionContext jobCtx)\n            throws JobExecutionException {\n        TopicConnection conn = null;\n\n        TopicSession sess = null;\n\n        TopicPublisher publisher = null;\n\n        try {\n            final JobDataMap dataMap = jobCtx.getMergedJobDataMap();\n\n            final Context namingCtx = JmsHelper.getInitialContext(dataMap);\n\n            final TopicConnectionFactory connFactory = (TopicConnectionFactory) namingCtx\n                    .lookup(dataMap\n                            .getString(JmsHelper.JMS_CONNECTION_FACTORY_JNDI));\n\n            if (!JmsHelper.isDestinationSecure(dataMap)) {\n                conn = connFactory.createTopicConnection();\n            } else {\n                final String user = dataMap.getString(JmsHelper.JMS_USER);\n\n                final String password = dataMap\n                        .getString(JmsHelper.JMS_PASSWORD);\n\n                conn = connFactory.createTopicConnection(user, password);\n            }\n\n            final boolean useTransaction = JmsHelper.useTransaction(dataMap);\n\n            final int ackMode = dataMap.getInt(JmsHelper.JMS_ACK_MODE);\n\n            sess = conn.createTopicSession(useTransaction, ackMode);\n\n            final Topic topic = (Topic) namingCtx.lookup(dataMap\n                    .getString(JmsHelper.JMS_DESTINATION_JNDI));\n\n            publisher = sess.createPublisher(topic);\n\n            final JmsMessageFactory messageFactory = JmsHelper\n                    .getMessageFactory(dataMap\n                            .getString(JmsHelper.JMS_MSG_FACTORY_CLASS_NAME));\n\n            final Message msg = messageFactory.createMessage(dataMap, sess);\n\n            publisher.publish(msg);\n        } catch (final Exception e) {\n            throw new JobExecutionException(e);\n        } finally {\n            JmsHelper.closeResource(publisher);\n\n            JmsHelper.closeResource(sess);\n\n            JmsHelper.closeResource(conn);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/jmx/JMXInvokerJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.jmx;\n\n\nimport java.util.LinkedList;\nimport java.util.StringTokenizer;\n\nimport javax.management.MBeanServer;\nimport javax.management.MBeanServerFactory;\nimport javax.management.ObjectName;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n\n/**\n * Generic JMX invoker Job.  It supports any number or type of parameters\n * to the JMX bean.<p>\n * \n * The required parameters are as follows (case doesn't matter):\n * <dl>\n * <dt><strong>JMX_OBJECTNAME</strong></dt>\n * <dd>This is the fully qualified name of the object (ie in JBoss to lookup\n * the log4j jmx bean you would specify \"jboss.system:type=Log4jService,service=Logging\"</dd>\n * <dt><strong>JMX_METHOD</strong></dt>\n * <dd>This is the method to invoke on the specified JMX Bean. (ie in JBoss to\n * change the log level you would specify \"setLoggerLevel\"</dd>\n * <dt><strong>JMX_PARAMDEFS</strong></dt>\n * <dd>This is a definition of the parameters to be passed to the specified method\n * and their corresponding java types.  Each parameter definition is comma separated\n * and has the following parts: &lt;type&gt;:&lt;name&gt;.  Type is the java type for the parameter.  \n * The following types are supported:<br>\n * <b>i</b> - is for int<br>\n * <b>l</b> - is for long<br>\n * <b>f</b> - is for float<br>\n * <b>d</b> - is for double<br>\n * <b>s</b> - is for String<br>\n * <b>b</b> - is for boolean<br>\n * For ilfdb use lower for native type and upper for object wrapper. The name portion\n * of the definition is the name of the parameter holding the string value. (ie\n * s:fname,s:lname would require 2 parameters of the name fname and lname and\n * would be passed in that order to the method.</dd>\n * </dl>\n * \n * @author James Nelson (jmn@provident-solutions.com) -- Provident Solutions LLC\n * \n */\npublic class JMXInvokerJob implements Job {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n        try {\n            Object[] params=null;\n            String[] types=null;\n            String objName = null;\n            String objMethod = null;\n            \n            JobDataMap jobDataMap = context.getMergedJobDataMap();\n            \n            String[] keys = jobDataMap.getKeys();\n            for (int i = 0; i < keys.length; i++) {\n                String value = jobDataMap.getString(keys[i]);\n                if (\"JMX_OBJECTNAME\".equalsIgnoreCase(keys[i])) {\n                    objName = value;\n                } else if (\"JMX_METHOD\".equalsIgnoreCase(keys[i])) {\n                    objMethod = value;\n                } else if(\"JMX_PARAMDEFS\".equalsIgnoreCase(keys[i])) {\n                    String[] paramdefs=split(value, \",\");\n                    params=new Object[paramdefs.length];\n                    types=new String[paramdefs.length];\n                    for(int k=0;k<paramdefs.length;k++) {\n                        String parts[]=  split(paramdefs[k], \":\");\n                        if (parts.length<2) {\n                            throw new Exception(\"Invalid parameter definition: required parts missing \"+paramdefs[k]);\n                        }\n                        switch(parts[0].charAt(0)) {\n                            case 'i':\n                                params[k]=Integer.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Integer.TYPE.getName();\n                                break;\n                            case 'I':\n                                params[k]=Integer.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Integer.class.getName();\n                                break;\n                            case 'l':\n                                params[k]=Long.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Long.TYPE.getName();\n                                break;\n                            case 'L':\n                                params[k]=Long.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Long.class.getName();\n                                break;\n                            case 'f':\n                                params[k]=Float.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Float.TYPE.getName();\n                                break;\n                            case 'F':\n                                params[k]=Float.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Float.class.getName();\n                                break;\n                            case 'd':\n                                params[k]=Double.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Double.TYPE.getName();\n                                break;\n                            case 'D':\n                                params[k]=Double.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Double.class.getName();\n                                break;\n                            case 's':\n                                params[k]=jobDataMap.getString(parts[1]);\n                                types[k]=String.class.getName();\n                                break;\n                            case 'b':\n                                params[k]= Boolean.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Boolean.TYPE.getName();\n                                break;\n                            case 'B':\n                                params[k]= Boolean.valueOf(jobDataMap.getString(parts[1]));\n                                types[k]=Boolean.class.getName();\n                                break;\n                        }\n                    }\n                }\n            }\n            \n            if (objName==null || objMethod==null) { \n                throw new Exception(\"Required parameters missing\");\n            }\n            \n            context.setResult(invoke(objName, objMethod, params, types));\n        } catch (Exception e) {\n            String m = \"Caught a \" + e.getClass().getName() + \" exception : \" + e.getMessage();\n            getLog().error(m, e);\n            throw new JobExecutionException(m, e, false);\n        }\n    }\n  \n    private String[] split(String str, String splitStr) // Same as String.split(.) in JDK 1.4\n    {\n        LinkedList<String> l = new LinkedList<String>();\n    \n        StringTokenizer strTok = new StringTokenizer(str, splitStr);\n        while(strTok.hasMoreTokens()) {\n            String tok = strTok.nextToken();\n            l.add(tok);\n        }\n    \n        return (String[])l.toArray(new String[l.size()]);\n    }\n\n    private Object invoke(String objectName, String method, Object[] params, String[] types) throws Exception {\n        MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);\n        ObjectName mbean = new ObjectName(objectName);\n\n        if (server == null) {\n            throw new Exception(\"Can't find mbean server\");\n        }\n\n        getLog().info(\"invoking \" + method);\n        return server.invoke(mbean, method, params, types);\n    }\n\n    protected Logger getLog() {\n        return log;\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/main/java/org/quartz/jobs/ee/mail/SendMailJob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs.ee.mail;\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport jakarta.mail.Address;\nimport jakarta.mail.Authenticator;\nimport jakarta.mail.Message;\nimport jakarta.mail.MessagingException;\nimport jakarta.mail.PasswordAuthentication;\nimport jakarta.mail.Session;\nimport jakarta.mail.Transport;\nimport jakarta.mail.internet.InternetAddress;\nimport jakarta.mail.internet.MimeMessage;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * <p>\n * A Job which sends an e-mail with the configured content to the configured\n * recipient.\n * \n * Arbitrary mail.smtp.xxx settings can be added to job data and they will be\n * passed along the mail session\n * </p>\n * \n * @author James House\n */\npublic class SendMailJob implements Job {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Constants.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * The host name of the smtp server. REQUIRED.\n     */\n    public static final String PROP_SMTP_HOST = \"smtp_host\";\n\n    /**\n     * The e-mail address to send the mail to. REQUIRED.\n     */\n    public static final String PROP_RECIPIENT = \"recipient\";\n\n    /**\n     * The e-mail address to cc the mail to. Optional.\n     */\n    public static final String PROP_CC_RECIPIENT = \"cc_recipient\";\n\n    /**\n     * The e-mail address to claim the mail is from. REQUIRED.\n     */\n    public static final String PROP_SENDER = \"sender\";\n\n    /**\n     * The e-mail address the message should say to reply to. Optional.\n     */\n    public static final String PROP_REPLY_TO = \"reply_to\";\n\n    /**\n     * The subject to place on the e-mail. REQUIRED.\n     */\n    public static final String PROP_SUBJECT = \"subject\";\n\n    /**\n     * The e-mail message body. REQUIRED.\n     */\n    public static final String PROP_MESSAGE = \"message\";\n\n    /**\n     * The message content type. For example, \"text/html\". Optional.\n     */\n    public static final String PROP_CONTENT_TYPE = \"content_type\";\n    \n    /**\n     * Username for authenticated session. Password must also be set if username is used. Optional.\n     */\n    public static final String PROP_USERNAME = \"username\";\n    \n    /**\n     * Password for authenticated session. Optional.\n     */\n    public static final String PROP_PASSWORD = \"password\";    \n\n    /*\n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     * \n     * Interface.\n     * \n     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     */\n\n    /**\n     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)\n     */\n    public void execute(JobExecutionContext context)\n        throws JobExecutionException {\n\n        JobDataMap data = context.getMergedJobDataMap();\n\n        MailInfo mailInfo = populateMailInfo(data, createMailInfo());\n        \n        getLog().info(\"Sending message \" + mailInfo);\n\n        try {\n            MimeMessage mimeMessage = prepareMimeMessage(mailInfo);\n            \n            Transport.send(mimeMessage);\n        } catch (MessagingException e) {\n            throw new JobExecutionException(\"Unable to send mail: \" + mailInfo,\n                    e, false);\n        }\n\n    }\n\n    protected Logger getLog() {\n        return log;\n    }\n\n    protected MimeMessage prepareMimeMessage(MailInfo mailInfo)\n        throws MessagingException {\n        Session session = getMailSession(mailInfo);\n\n        MimeMessage mimeMessage = new MimeMessage(session);\n\n        Address[] toAddresses = InternetAddress.parse(mailInfo.getTo());\n        mimeMessage.setRecipients(Message.RecipientType.TO, toAddresses);\n\n        if (mailInfo.getCc() != null) {\n            Address[] ccAddresses = InternetAddress.parse(mailInfo.getCc());\n            mimeMessage.setRecipients(Message.RecipientType.CC, ccAddresses);\n        }\n\n        mimeMessage.setFrom(new InternetAddress(mailInfo.getFrom()));\n        \n        if (mailInfo.getReplyTo() != null) {\n            mimeMessage.setReplyTo(new InternetAddress[]{new InternetAddress(mailInfo.getReplyTo())});\n        }\n        \n        mimeMessage.setSubject(mailInfo.getSubject());\n        \n        mimeMessage.setSentDate(new Date());\n\n        setMimeMessageContent(mimeMessage, mailInfo);\n\n        return mimeMessage;\n    }\n    \n    protected void setMimeMessageContent(MimeMessage mimeMessage, MailInfo mailInfo) \n        throws MessagingException {\n        if (mailInfo.getContentType() == null) {\n            mimeMessage.setText(mailInfo.getMessage());\n        } else {\n            mimeMessage.setContent(mailInfo.getMessage(), mailInfo.getContentType());\n        }\n    }\n\n    protected Session getMailSession(final MailInfo mailInfo) throws MessagingException {\n        Properties properties = new Properties();\n        properties.put(\"mail.smtp.host\", mailInfo.getSmtpHost());\n        \n        // pass along extra smtp settings from users\n        Properties extraSettings = mailInfo.getSmtpProperties();\n        if (extraSettings != null) {\n            properties.putAll(extraSettings);\n        }\n        \n        Authenticator authenticator = null;\n        if (mailInfo.getUsername() != null && mailInfo.getPassword() != null) {\n            log.info(\"using username '{}' and password 'xxx'\", mailInfo.getUsername());\n            authenticator = new Authenticator() { \n                protected PasswordAuthentication getPasswordAuthentication() { \n                    return new PasswordAuthentication(mailInfo.getUsername(), mailInfo.getPassword()); \n                }\n            };\n        }\n        log.debug(\"Sending mail with properties: {}\", properties);\n        return Session.getDefaultInstance(properties, authenticator);\n    }\n    \n    protected MailInfo createMailInfo() {\n        return new MailInfo();\n    }\n    \n    protected MailInfo populateMailInfo(JobDataMap data, MailInfo mailInfo) {\n        // Required parameters\n        mailInfo.setSmtpHost(getRequiredParm(data, PROP_SMTP_HOST, \"PROP_SMTP_HOST\"));\n        mailInfo.setTo(getRequiredParm(data, PROP_RECIPIENT, \"PROP_RECIPIENT\"));\n        mailInfo.setFrom(getRequiredParm(data, PROP_SENDER, \"PROP_SENDER\"));\n        mailInfo.setSubject(getRequiredParm(data, PROP_SUBJECT, \"PROP_SUBJECT\"));\n        mailInfo.setMessage(getRequiredParm(data, PROP_MESSAGE, \"PROP_MESSAGE\"));\n        \n        // Optional parameters\n        mailInfo.setReplyTo(getOptionalParm(data, PROP_REPLY_TO));\n        mailInfo.setCc(getOptionalParm(data, PROP_CC_RECIPIENT));\n        mailInfo.setContentType(getOptionalParm(data, PROP_CONTENT_TYPE));\n        mailInfo.setUsername(getOptionalParm(data, PROP_USERNAME));\n        mailInfo.setPassword(getOptionalParm(data, PROP_PASSWORD));\n        \n        // extra mail.smtp. properties from user\n        Properties smtpProperties = new Properties();\n        for (String key : data.keySet()) {\n            if (key.startsWith(\"mail.smtp.\")) {\n                smtpProperties.put(key, data.getString(key));\n            }\n        }\n        if (mailInfo.getSmtpProperties() == null) {\n            mailInfo.setSmtpProperties(smtpProperties);\n        } else {\n            mailInfo.getSmtpProperties().putAll(smtpProperties);\n        }\n\n        \n        return mailInfo;\n    }\n    \n    \n    protected String getRequiredParm(JobDataMap data, String property, String constantName) {\n        String value = getOptionalParm(data, property);\n        \n        if (value == null) {\n            throw new IllegalArgumentException(constantName + \" not specified.\");\n        }\n        \n        return value;\n    }\n    \n    protected String getOptionalParm(JobDataMap data, String property) {\n        String value = data.getString(property);\n        \n        if ((value != null) && (value.trim().length() == 0)) {\n            return null;\n        }\n        \n        return value;\n    }\n    \n    protected static class MailInfo {\n        private String smtpHost;\n        private String to;\n        private String from;\n        private String subject;\n        private String message;\n        private String replyTo;\n        private String cc;\n        private String contentType;\n        private String username;\n        private String password;\n        private Properties smtpProperties;\n\n        @Override\n        public String toString() {\n            return \"'\" + getSubject() + \"' to: \" + getTo();\n        }\n        \n        public String getCc() {\n            return cc;\n        }\n\n        public void setCc(String cc) {\n            this.cc = cc;\n        }\n\n        public String getContentType() {\n            return contentType;\n        }\n\n        public void setContentType(String contentType) {\n            this.contentType = contentType;\n        }\n\n        public String getFrom() {\n            return from;\n        }\n\n        public void setFrom(String from) {\n            this.from = from;\n        }\n\n        public String getMessage() {\n            return message;\n        }\n\n        public void setMessage(String message) {\n            this.message = message;\n        }\n\n        public String getReplyTo() {\n            return replyTo;\n        }\n\n        public void setReplyTo(String replyTo) {\n            this.replyTo = replyTo;\n        }\n\n        public String getSmtpHost() {\n            return smtpHost;\n        }\n\n        public void setSmtpHost(String smtpHost) {\n            this.smtpHost = smtpHost;\n        }\n\n        public String getSubject() {\n            return subject;\n        }\n\n        public void setSubject(String subject) {\n            this.subject = subject;\n        }\n\n        public String getTo() {\n            return to;\n        }\n\n        public void setTo(String to) {\n            this.to = to;\n        }\n        \n        public Properties getSmtpProperties() {\n            return smtpProperties;\n        }\n        \n        public void setSmtpProperties(Properties smtpProperties) {\n            this.smtpProperties = smtpProperties;\n        }\n        \n        public String getUsername() {\n            return username;\n        }\n        \n        public void setUsername(String username) {\n            this.username = username;\n        }\n        \n        public String getPassword() {\n            return password;\n        }\n        \n        public void setPassword(String password) {\n            this.password = password;\n        }\n    }\n}\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/integrations/tests/AutoInterruptableJobTest.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy\n * of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage org.quartz.integrations.tests;\n\n\nimport static org.quartz.JobBuilder.newJob;\nimport static org.quartz.TriggerBuilder.newTrigger;\n\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport junit.framework.TestCase;\n\n\nimport org.quartz.*;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.plugins.interrupt.JobInterruptMonitorPlugin;\n\n/**\n * AutoInterruptable Job Monitor test\n * \n * @see org.quartz.Scheduler#interrupt()\n * \n * @author Rama Chavali\n */\n \npublic class AutoInterruptableJobTest extends TestCase {\n\n    static final CyclicBarrier sync = new CyclicBarrier(2);\n\n    public static class TestInterruptableJob implements InterruptableJob {\n\n        public static final AtomicBoolean interrupted = new AtomicBoolean(false);\n        \n        public void execute(JobExecutionContext context)\n                throws JobExecutionException {\n            System.out.println(\"TestInterruptableJob is executing.\");\n            try {\n                sync.await(); // wait for test thread to notice the job is now running\n            } catch (InterruptedException e1) {\n            } catch (BrokenBarrierException e1) {\n            }\n            for(int i=0; i < 200; i++) {\n                try {\n                    Thread.sleep(50); // simulate being busy for a while, then checking interrupted flag...\n                } catch (InterruptedException ignore) { }\n                if(TestInterruptableJob.interrupted.get()) {\n                    System.out.println(\"TestInterruptableJob main loop detected interrupt signal.\");\n                    break;\n                }\n            }\n            try {\n                System.out.println(\"TestInterruptableJob exiting with interrupted = \" + interrupted);\n                sync.await();\n            } catch (InterruptedException e) {\n            } catch (BrokenBarrierException e) {\n            }\n        }\n\n        public void interrupt() throws UnableToInterruptJobException {\n            TestInterruptableJob.interrupted.set(true);\n            System.out.println(\"TestInterruptableJob.interrupt() called.\");\n        }\n    }\n    \n    @Override\n    protected void setUp() throws Exception {\n    }\n\n    public void testJobAutoInterruption() throws Exception {\n        \n        // create a simple scheduler\n        \n        Properties config = new Properties();\n        config.setProperty(\"org.quartz.scheduler.instanceName\", \"InterruptableJobTest_Scheduler\");\n        config.setProperty(\"org.quartz.scheduler.instanceId\", \"AUTO\");\n        config.setProperty(\"org.quartz.threadPool.threadCount\", \"2\");\n        config.setProperty(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\n        config.setProperty(\"org.quartz.plugin.jobInterruptor.class\", \"org.quartz.plugins.interrupt.JobInterruptMonitorPlugin\");\n        config.setProperty(\"org.quartz.plugin.jobInterruptor.defaultMaxRunTime\", \"1000\");\n        Scheduler sched = new StdSchedulerFactory(config).getScheduler();\n        sched.start();\n\n        // add a job with a trigger that will fire immediately\n        \n        JobDataMap jobDataMap = new JobDataMap();\n        jobDataMap.put(JobInterruptMonitorPlugin.AUTO_INTERRUPTIBLE, \"true\");\n        JobDetail job = newJob()\n            .ofType(TestInterruptableJob.class)\n            .withIdentity(\"j1\")\n            .setJobData(jobDataMap)\n            .build();\n\n        Trigger trigger = newTrigger()\n            .withIdentity(\"t1\")\n            .forJob(job)\n            .startNow()\n            .build();\n\n        sched.scheduleJob(job, trigger);\n        \n        sync.await();  // make sure the job starts running...\n        \n        List<JobExecutionContext> executingJobs = sched.getCurrentlyExecutingJobs();\n        \n        assertTrue(\"Number of executing jobs should be 1 \", executingJobs.size() == 1);\n                \n        sync.await(); // wait for the job to terminate\n\n\n        assertTrue(\"Expected interrupted flag to be set on job class \", TestInterruptableJob.interrupted.get());\n        \n        sched.clear();\n\n        sched.shutdown();\n    }\n\n}\n\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/integrations/tests/DummyClassLoadHelper.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport org.quartz.simpl.CascadingClassLoadHelper;\n\n\n/**\n * \n * Always mimic CascadingClassLoadHelper except...\n * when looking for OnlyVisibleByDummyClassLoadHelperJob\n * \n * @author adahanne\n *\n */\npublic class DummyClassLoadHelper extends CascadingClassLoadHelper {\n  \n  @Override\n  public Class<?> loadClass(String className) throws ClassNotFoundException {\n\t  if(className.equals(\"imaginary.class.OnlyVisibleByDummyClassLoadHelperJob\")){\n\t\t  //we just translate the className ! Only DummyClassLoadHelper is able to do that !\n\t\t  className = \"org.quartz.integrations.tests.HelloJob\";\n\t  }\n\t  return super.loadClass(className);\n\t  \n  }\n\n}"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/integrations/tests/HelloJob.java",
    "content": "package org.quartz.integrations.tests;\n\n/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\nimport java.util.Date;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * This is just a simple job that says \"Hello\" to the world.\n * </p>\n * \n * @author Bill Kratzer\n */\npublic class HelloJob implements Job {\n\n    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);\n\n    /**\n     * <p>\n     * Empty constructor for job initialization\n     * </p>\n     * <p>\n     * Quartz requires a public empty constructor so that the scheduler can\n     * instantiate the class whenever it needs.\n     * </p>\n     */\n    public HelloJob() {\n    }\n\n    /**\n     * <p>\n     * Called by the <code>{@link org.quartz.Scheduler}</code> when a\n     * <code>{@link org.quartz.Trigger}</code> fires that is associated with the\n     * <code>Job</code>.\n     * </p>\n     * \n     * @throws JobExecutionException\n     *             if there is an exception while executing the job.\n     */\n    public void execute(JobExecutionContext context) throws JobExecutionException {\n\n        // Say Hello to the World and display the date/time\n        _log.info(\"Hello World! - \" + new Date());\n    }\n\n}\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/integrations/tests/QTZ225_SchedulerClassLoadHelperForPlugins_Test.java",
    "content": "/*\n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.quartz.integrations.tests;\n\nimport static org.junit.Assert.fail;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * This test is rather a \"smoke test\"\n * \n * It will configure the scheduler with a DummyClassLoadHelper (that extends\n * CascadeClassLoadHelper) and using the XMLSchedulingDataProcessorPlugin\n * \n * The job class configured in quartz_data.xml does not exist.\n * \n * This test passes only if the plugin uses, like the SchedulerFactory does, the\n * DummyClassLoadHelper which is capable to load this imaginary job class\n * (previous behavior was : always instantiates the CascadeClassLoadHelper , not\n * considering the SchedulerFactory classLoadHelper)\n * \n * @author adahanne\n * \n */\npublic class QTZ225_SchedulerClassLoadHelperForPlugins_Test {\n\n    private Scheduler sched;\n    Logger log = LoggerFactory.getLogger(QTZ225_SchedulerClassLoadHelperForPlugins_Test.class);\n\n    @Before\n    public void setUp() throws SchedulerException {\n\n        // First we must get a reference to a scheduler\n        SchedulerFactory sf = new StdSchedulerFactory(\"org/quartz/tests/QTZ225/quartz.properties\");\n        sched = sf.getScheduler();\n\n        log.info(\"------- Initialization Complete -----------\");\n\n        log.info(\"------- (Not Scheduling any Jobs - relying on XML definitions --\");\n\n        log.info(\"------- Starting Scheduler ----------------\");\n\n        // start the schedule\n        sched.start();\n    }\n\n    @Test\n    public void dummyClassLoadHelperSuccessfullyLoadedImaginaryJobClassTest() throws SchedulerException {\n        if (!sched.checkExists(new JobKey(\"ImaginaryJob\"))) {\n            fail(\"The dummy job was not added to the scheduler, certainly because the dummy classloadhelper was not used by the plugin\");\n        }\n    }\n\n    @After\n    public void tearDown() throws SchedulerException {\n        log.info(\"------- Shutting down Scheduler ----------------\");\n        sched.shutdown();\n\n    }\n}\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/MyJobListener.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport java.util.concurrent.CyclicBarrier;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport org.quartz.JobExecutionContext;\r\nimport org.quartz.JobExecutionException;\r\nimport org.quartz.JobListener;\r\n\r\npublic class MyJobListener implements JobListener {\r\n    public volatile JobExecutionException jobException;\r\n    public CyclicBarrier barrier = new CyclicBarrier(2);\r\n\r\n    @Override\r\n    public String getName() {\r\n        return \"MyJobListener\";\r\n    }\r\n\r\n    @Override\r\n    public void jobToBeExecuted(JobExecutionContext context) {\r\n        //\r\n    }\r\n\r\n    @Override\r\n    public void jobExecutionVetoed(JobExecutionContext context) {\r\n        //\r\n    }\r\n\r\n    @Override\r\n    public void jobWasExecuted(JobExecutionContext context,\r\n            JobExecutionException jobException) {\r\n        this.jobException = jobException;\r\n        try {\r\n            barrier.await(30, TimeUnit.SECONDS);\r\n        } catch (Exception e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/SendMailJobAuthTestBase.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport static org.quartz.JobBuilder.newJob;\r\nimport static org.quartz.TriggerBuilder.newTrigger;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport org.junit.After;\r\nimport org.junit.Before;\r\nimport org.junit.Test;\r\nimport org.quartz.JobDataMap;\r\nimport org.quartz.JobDetail;\r\nimport org.quartz.Scheduler;\r\nimport org.quartz.Trigger;\r\nimport org.quartz.impl.StdSchedulerFactory;\r\nimport org.quartz.jobs.ee.mail.SendMailJob;\r\nimport org.subethamail.smtp.auth.PlainAuthenticationHandlerFactory;\r\nimport org.subethamail.wiser.Wiser;\r\n\r\npublic abstract class SendMailJobAuthTestBase {\r\n    private Wiser wiser;\r\n    private Scheduler scheduler;\r\n    protected SimpleValidator simpleValidator;\r\n    protected MyJobListener jobListener;\r\n    private final String sender;\r\n    private final String username;\r\n    private final String password;\r\n    \r\n    public SendMailJobAuthTestBase(String sender, String username, String password) {\r\n        this.sender = sender;\r\n        this.username = username;\r\n        this.password = password;\r\n    }\r\n\r\n    @Before\r\n    public void setUp() throws Exception {\r\n        simpleValidator = new SimpleValidator();\r\n        wiser = new Wiser(2500);\r\n        wiser.getServer()\r\n                .setAuthenticationHandlerFactory(new PlainAuthenticationHandlerFactory(\r\n                        simpleValidator));\r\n        wiser.start();\r\n        \r\n        // set up scheduler\r\n        jobListener = new MyJobListener();\r\n        scheduler = new StdSchedulerFactory().getScheduler();\r\n        scheduler.getListenerManager().addJobListener(jobListener);\r\n    }\r\n\r\n    @After\r\n    public void tearDown() throws Exception {\r\n        wiser.stop();\r\n        scheduler.shutdown(true);\r\n    }\r\n\r\n    @Test\r\n    public void testWithAuthentication() throws Exception {\r\n        JobDetail job = newJob(SendMailJob.class)\r\n                .withIdentity(\"job1\", \"group1\").build();\r\n\r\n        configureSendMailJob(job);\r\n\r\n        Trigger trigger = newTrigger().withIdentity(\"trigger1\", \"group1\")\r\n                .startNow().build();\r\n\r\n        scheduler.scheduleJob(job, trigger);\r\n        scheduler.start();\r\n\r\n        jobListener.barrier.await(30, TimeUnit.SECONDS);\r\n        \r\n        assertAuthentication();\r\n    }\r\n    \r\n    public abstract void assertAuthentication() throws Exception;\r\n\r\n    protected void configureSendMailJob(JobDetail job) {\r\n        JobDataMap jobData = job.getJobDataMap();\r\n        jobData.put(SendMailJob.PROP_SMTP_HOST, \"localhost\");\r\n        jobData.put(SendMailJob.PROP_SENDER, sender);\r\n        jobData.put(SendMailJob.PROP_RECIPIENT, \"receiver@host.com\");\r\n        jobData.put(SendMailJob.PROP_SUBJECT, \"test subject\");\r\n        jobData.put(SendMailJob.PROP_MESSAGE, \"do not reply\");\r\n        jobData.put(SendMailJob.PROP_USERNAME, username);\r\n        jobData.put(SendMailJob.PROP_PASSWORD, password);\r\n        jobData.put(\"mail.smtp.port\", \"2500\");\r\n        jobData.put(\"mail.smtp.auth\", \"true\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/SendMailJobFakeAuth.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport static org.hamcrest.CoreMatchers.instanceOf;\r\nimport static org.hamcrest.Matchers.notNullValue;\r\nimport static org.junit.Assert.assertThat;\r\n\r\nimport org.junit.Ignore;\r\nimport org.subethamail.smtp.auth.LoginFailedException;\r\n\r\n@Ignore\r\npublic class SendMailJobFakeAuth extends SendMailJobAuthTestBase {\r\n    public SendMailJobFakeAuth() {\r\n        super(\"fake@host.name\", \"fakeusername\", \"fakepassword\");\r\n    }\r\n\r\n    @Override\r\n    public void assertAuthentication() throws Exception {\r\n        assertThat(this.jobListener.jobException, notNullValue());\r\n        assertThat(this.simpleValidator.error, instanceOf(LoginFailedException.class));\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/SendMailJobRealAuth.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport org.junit.Ignore;\r\n\r\nimport static org.hamcrest.CoreMatchers.nullValue;\r\nimport static org.junit.Assert.assertThat;\r\n\r\n@Ignore\r\npublic class SendMailJobRealAuth extends SendMailJobAuthTestBase {\r\n    public SendMailJobRealAuth() {\r\n        super(\"real@host.name\", \"realusername\", \"realpassword\");\r\n    }\r\n\r\n    @Override\r\n    public void assertAuthentication() throws Exception {\r\n        assertThat(this.jobListener.jobException, nullValue());\r\n        assertThat(this.simpleValidator.error, nullValue());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/SendMailJobTest.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport static org.hamcrest.Matchers.equalTo;\r\nimport static org.junit.Assert.assertThat;\r\nimport static org.quartz.JobBuilder.newJob;\r\nimport static org.quartz.SimpleScheduleBuilder.simpleSchedule;\r\nimport static org.quartz.TriggerBuilder.newTrigger;\r\n\r\nimport java.util.Properties;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport jakarta.mail.Message;\r\nimport jakarta.mail.MessagingException;\r\nimport jakarta.mail.PasswordAuthentication;\r\nimport jakarta.mail.Session;\r\nimport jakarta.mail.Transport;\r\nimport jakarta.mail.internet.InternetAddress;\r\nimport jakarta.mail.internet.MimeMessage;\r\n\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.junit.After;\r\nimport org.junit.Before;\r\nimport org.junit.Ignore;\r\nimport org.junit.Test;\r\nimport org.quartz.JobDataMap;\r\nimport org.quartz.JobDetail;\r\nimport org.quartz.Scheduler;\r\nimport org.quartz.SimpleTrigger;\r\nimport org.quartz.impl.StdSchedulerFactory;\r\nimport org.quartz.jobs.ee.mail.SendMailJob;\r\nimport org.subethamail.wiser.Wiser;\r\nimport org.subethamail.wiser.WiserMessage;\r\n\r\n@Ignore\r\npublic class SendMailJobTest {\r\n    private Wiser wiser;\r\n    private Scheduler scheduler;\r\n    private MyJobListener jobListener;\r\n\r\n    @Before\r\n    public void setup() throws Exception {\r\n        wiser = new Wiser();\r\n        wiser.setPort(2500);\r\n        wiser.start();\r\n        jobListener = new MyJobListener();\r\n        scheduler = StdSchedulerFactory.getDefaultScheduler();\r\n        scheduler.getListenerManager().addJobListener(jobListener);\r\n    }\r\n\r\n    @After\r\n    public void tearDown() throws Exception {\r\n        scheduler.shutdown();\r\n        wiser.stop();\r\n    }\r\n\r\n    @Test\r\n    public void testSendMailJobNoAuthentication() throws Exception {\r\n        JobDetail job = newJob(SendMailJob.class)\r\n                .withIdentity(\"job1\", \"group1\").build();\r\n\r\n        JobDataMap jobData = job.getJobDataMap();\r\n        jobData.put(SendMailJob.PROP_SMTP_HOST, \"localhost\");\r\n        jobData.put(SendMailJob.PROP_SENDER, \"sender@host.com\");\r\n        jobData.put(SendMailJob.PROP_RECIPIENT, \"receiver@host.com\");\r\n        jobData.put(SendMailJob.PROP_SUBJECT, \"test subject\");\r\n        jobData.put(SendMailJob.PROP_MESSAGE, \"do not reply\");\r\n        jobData.put(\"mail.smtp.port\", \"2500\");\r\n\r\n        SimpleTrigger trigger = newTrigger()\r\n                .withIdentity(\"trigger1\", \"group1\")\r\n                .startNow()\r\n                .withSchedule(\r\n                        simpleSchedule().withIntervalInSeconds(120)\r\n                                .withRepeatCount(1)).build();\r\n\r\n        scheduler.scheduleJob(job, trigger);\r\n        scheduler.start();\r\n        \r\n        jobListener.barrier.await(30, TimeUnit.SECONDS);\r\n\r\n        assertThat(wiser.getMessages().size(), equalTo(1));\r\n\r\n        WiserMessage message = wiser.getMessages().get(0);\r\n        System.out.println(message);\r\n        System.out.println(message.getMimeMessage().getSubject());\r\n        assertThat(message.getEnvelopeSender(), equalTo(\"sender@host.com\"));\r\n        assertThat(message.getEnvelopeReceiver(), equalTo(\"receiver@host.com\"));\r\n        assertThat(message.getMimeMessage().getSubject(), equalTo(\"test subject\"));\r\n        assertThat(IOUtils.toString(message.getMimeMessage().getInputStream())\r\n                .trim(), equalTo(\"do not reply\"));\r\n    }\r\n\r\n    /**\r\n     * replace xxx with your real credentials\r\n     * \r\n     * @throws Exception\r\n     */\r\n    @Ignore\r\n    @Test\r\n    public void testRealAccountSendMail() throws Exception {\r\n        Properties props = new Properties();\r\n        props.put(\"mail.smtp.auth\", \"true\");\r\n        props.put(\"mail.smtp.port\", \"465\");\r\n        props.put(\"mail.smtp.ssl.enable\", \"true\");\r\n        props.put(\"mail.smtp.host\", \"smtp.gmail.com\");\r\n        props.put(\"mail.debug\", \"true\");\r\n        Session session = Session.getInstance(props,\r\n                new jakarta.mail.Authenticator() {\r\n                    protected PasswordAuthentication getPasswordAuthentication() {\r\n                        return new PasswordAuthentication(\"xxx\", \"xxx\");\r\n                    }\r\n                });\r\n        try {\r\n            Message message = new MimeMessage(session);\r\n            message.setFrom(new InternetAddress(\"xxx@gmail.com\"));\r\n            message.setRecipients(Message.RecipientType.TO,\r\n                    InternetAddress.parse(\"xxx@gmail.com\"));\r\n            message.setSubject(\"Test Subject\");\r\n            message.setText(\"Test message\");\r\n            Transport.send(message);\r\n            System.out.println(\"Sent\");\r\n\r\n        } catch (MessagingException e) {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/java/org/quartz/jobs/SimpleValidator.java",
    "content": "package org.quartz.jobs;\r\n\r\nimport static org.hamcrest.Matchers.equalTo;\r\nimport static org.junit.Assert.assertThat;\r\n\r\nimport org.subethamail.smtp.auth.LoginFailedException;\r\nimport org.subethamail.smtp.auth.UsernamePasswordValidator;\r\n\r\nclass SimpleValidator implements UsernamePasswordValidator {\r\n    public LoginFailedException error;\r\n\r\n    @Override\r\n    public void login(String username, String password)\r\n            throws LoginFailedException {\r\n        System.out.println(\"UsernamePasswordValidator: login username '\"\r\n                + username + \"' password '\" + password + \"'\");\r\n        try {\r\n            assertThat(username, equalTo(\"realusername\"));\r\n            assertThat(password, equalTo(\"realpassword\"));\r\n        } catch (Throwable e) {\r\n            error = new LoginFailedException(e.getMessage());\r\n            throw error;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "quartz-jobs/src/test/resources/log4j.properties",
    "content": "# Configure logging for testing\nlog4j.rootLogger=INFO, stdout\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n\n\nlog4j.logger.org.quartz.jobs.ee.mail=DEBUG\n"
  },
  {
    "path": "quartz-jobs/src/test/resources/org/quartz/tests/QTZ225/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\n  <appender name=\"default\" class=\"org.apache.log4j.ConsoleAppender\">\n    <param name=\"target\" value=\"System.out\"/>\n    <layout class=\"org.apache.log4j.PatternLayout\">\n      <param name=\"ConversionPattern\" value=\"[%p] %d{dd MMM hh:mm:ss.SSS aa} %t [%c]%n%m%n%n\"/>\n    </layout>\n  </appender>\n\n\n <logger name=\"org.quartz\">\n   <level value=\"debug\" />\n </logger>\n\n  <root>\n    <level value=\"info\" />\n    <appender-ref ref=\"default\" />\n  </root>\n\n  \n</log4j:configuration>\n"
  },
  {
    "path": "quartz-jobs/src/test/resources/org/quartz/tests/QTZ225/quartz.properties",
    "content": "\n#============================================================================\n# Configure Main Scheduler Properties  \n#============================================================================\n\norg.quartz.scheduler.instanceName: TestScheduler\norg.quartz.scheduler.instanceId: AUTO\n\norg.quartz.scheduler.classLoadHelper.class: org.quartz.integrations.tests.DummyClassLoadHelper\n#============================================================================\n# Configure ThreadPool  \n#============================================================================\n\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 3\norg.quartz.threadPool.threadPriority: 5\n\n#============================================================================\n# Configure JobStore  \n#============================================================================\n\norg.quartz.jobStore.misfireThreshold: 60000\n\norg.quartz.jobStore.class: org.quartz.simpl.RAMJobStore\n\n#============================================================================\n# Configure Plugins \n#============================================================================\n\norg.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin\n\norg.quartz.plugin.jobInitializer.class: org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin\norg.quartz.plugin.jobInitializer.fileNames: org/quartz/tests/QTZ225/quartz_data.xml\norg.quartz.plugin.jobInitializer.failOnFileNotFound: true\norg.quartz.plugin.jobInitializer.scanInterval: 120\norg.quartz.plugin.jobInitializer.wrapInUserTransaction: false\n\n"
  },
  {
    "path": "quartz-jobs/src/test/resources/org/quartz/tests/QTZ225/quartz_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<job-scheduling-data xmlns=\"http://www.quartz-scheduler.org/xml/JobSchedulingData\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd\"\n    version=\"2.0\">\n    \n    <pre-processing-commands>\n        <delete-jobs-in-group>*</delete-jobs-in-group>  <!-- clear all jobs in scheduler -->\n        <delete-triggers-in-group>*</delete-triggers-in-group> <!-- clear all triggers in scheduler -->\n    </pre-processing-commands>\n    \n    <processing-directives>\n        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), overwrite them -->\n        <overwrite-existing-data>true</overwrite-existing-data>\n        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), and over-write is false, ignore them rather then generating an error -->\n        <ignore-duplicates>false</ignore-duplicates> \n    </processing-directives>\n    \n    <schedule>\n\t    <job>\n\t        <name>ImaginaryJob</name>\n\t        <job-class>imaginary.class.OnlyVisibleByDummyClassLoadHelperJob</job-class>\n\t    </job>\n\t    \n        <trigger>\n\t        <simple>\n\t            <name>TestSimpleTrigger1AtFiveSecondInterval</name>\n\t            <job-name>ImaginaryJob</job-name>\n\t            <repeat-count>-1</repeat-count> <!-- repeat indefinitely  -->\n\t            <repeat-interval>5000</repeat-interval>  <!--  every 5 seconds -->\n\t        </simple>\n\t    </trigger>\n\t\n\t   \n    </schedule>    \n</job-scheduling-data>\n"
  },
  {
    "path": "quartz-stubs/build.gradle",
    "content": "plugins {\n    id 'java-library'\n}\n\ndependencies {\n    implementation \"org.slf4j:slf4j-api:$slf4jVersion\"\n    runtimeOnly \"org.slf4j:slf4j-log4j12:$slf4jVersion\"\n    testImplementation \"junit:junit:$junitVersion\"\n}\n\n"
  },
  {
    "path": "quartz-stubs/src/main/java/oracle/sql/BLOB.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage oracle.sql;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.sql.Blob;\nimport java.sql.SQLException;\n\npublic class BLOB implements Blob {\n\n  public long length() throws SQLException {\n    return 0;\n  }\n\n  public byte[] getBytes(long pos, int length) throws SQLException {\n    return null;\n  }\n\n  public InputStream getBinaryStream() throws SQLException {\n    return null;\n  }\n\n  public long position(byte[] pattern, long start) throws SQLException {\n    return 0;\n  }\n\n  public long position(Blob pattern, long start) throws SQLException {\n    return 0;\n  }\n\n  public int setBytes(long pos, byte[] bytes) throws SQLException {\n    return 0;\n  }\n\n  public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {\n    return 0;\n  }\n\n  public OutputStream setBinaryStream(long pos) throws SQLException {\n    return null;\n  }\n\n  public void truncate(long len) throws SQLException {\n    //\n  }\n\n  public void free() throws SQLException {\n    //\n  }\n\n  public InputStream getBinaryStream(long pos, long length) throws SQLException {\n    return null;\n  }\n\n  public int putBytes(long pos, byte[] data) throws SQLException {\n    return 0;\n  }\n\n  public void trim(long length) throws SQLException {\n    //\n  }\n\n}\n"
  },
  {
    "path": "quartz-stubs/src/main/java/org/quartz/jobs/DirectoryScanListener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\nimport java.io.File;\n\n/**\n * Interface for objects wishing to receive a 'call-back' from a \n * <code>DirectoryScanJob</code>.\n * \n * <p>Instances should be stored in the org.quartz.SchedulerContext\n * such that the <code>DirectoryScanJob</code> can find it.</p>\n * \n * @author jhouse\n */\npublic interface DirectoryScanListener {\n\n    /**\n     * @param updatedFiles The set of files that were updated/added since the\n     * last scan of the directory\n     */\n    void filesUpdatedOrAdded(File[] updatedFiles);\n}\n"
  },
  {
    "path": "quartz-stubs/src/main/java/org/quartz/jobs/FileScanListener.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage org.quartz.jobs;\n\n/**\n * Interface for objects wishing to receive a 'call-back' from a \n * <code>FileScanJob</code>.\n * \n * @author jhouse\n */\npublic interface FileScanListener {\n\n    void fileUpdated(String fileName);\n}\n"
  },
  {
    "path": "quartz-stubs/src/main/java/weblogic/jdbc/jts/Driver.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage weblogic.jdbc.jts;\n\nimport java.util.logging.Logger;\nimport java.sql.Connection;\nimport java.sql.DriverPropertyInfo;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\npublic class Driver implements java.sql.Driver {\n\n  public Connection connect(String url, Properties info) throws SQLException {\n    return null;\n  }\n\n  public boolean acceptsURL(String url) throws SQLException {\n    return false;\n  }\n\n  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {\n    return null;\n  }\n\n  public int getMajorVersion() {\n    return 0;\n  }\n\n  public int getMinorVersion() {\n    return 0;\n  }\n\n  public boolean jdbcCompliant() {\n    return false;\n  }\n\n  public Logger getParentLogger() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "quartz-stubs/src/main/java/weblogic/jdbc/vendor/oracle/OracleThinBlob.java",
    "content": "/* \n * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.\n * Copyright IBM Corp. 2024, 2025 \n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not \n * use this file except in compliance with the License. You may obtain a copy \n * of the License at \n * \n *   http://www.apache.org/licenses/LICENSE-2.0 \n *   \n * Unless required by applicable law or agreed to in writing, software \n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT \n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the \n * License for the specific language governing permissions and limitations \n * under the License.\n * \n */\n\npackage weblogic.jdbc.vendor.oracle;\n\nimport java.io.OutputStream;\nimport java.sql.SQLException;\n\npublic interface OracleThinBlob {\n\n  public abstract OutputStream getBinaryOutputStream() throws SQLException;\n\n  public abstract int getBufferSize() throws SQLException;\n\n  public abstract int getChunkSize() throws SQLException;\n\n  public abstract int putBytes(long l, byte abyte0[]) throws SQLException;\n\n  public abstract void truncate(long l) throws SQLException;\n\n  public abstract void trim(long l) throws SQLException;\n}\n"
  },
  {
    "path": "readme.adoc",
    "content": "== Quartz Scheduler\n\nQuartz is a richly featured, open source job scheduling library that can be \nintegrated within virtually any Java application - from the smallest stand-alone \napplication to the largest e-commerce system.\n\nSee <<docs/index.md#,Full Documentation>>\n\nStatus of the build:\n[link=\"https://dev.azure.com/TerracottaCI/quartz/_build/latest?definitionId=24\"]\nimage::https://dev.azure.com/TerracottaCI/quartz/_apis/build/status/quartz-scheduler.quartz[Build Status]\n\n== Quick Links\n\nhttps://www.quartz-scheduler.org/community/contribute.html\n\n"
  },
  {
    "path": "settings.gradle",
    "content": "\npluginManagement {\n    plugins {\n        id(\"io.github.gradle-nexus.publish-plugin\") version '2.0.0'\n        id (\"biz.aQute.bnd.builder\") version '6.4.0'\n    }\n}\n\nrootProject.name = 'quartz-scheduler'\n\ninclude 'quartz-stubs'\ninclude 'quartz-jobs'\ninclude 'quartz'\ninclude 'examples'\n\n"
  }
]